Inspiration

What it does

How we built it

Challenges we ran into

Accomplishments that we're proud of

What we learned

What's next for Synerdio# Synerdio

Inspiration

Pair debugging a live site is almost always worse than it needs to be. Someone screen-shares, and the other person spends half the session saying "scroll down," "no, the other button," "wait, refresh, I made a change." Everyone's staring at one person's cursor on one person's screen, and the moment you actually need to show someone a broken element or a slow network request, the tools break down into a game of verbal directions.

I wanted the opposite of that: everyone actually on the page at once, same cursors, same highlights, same live data without asking anyone to install anything or make an account. If I can paste one line into DevTools and my teammate can see exactly what I'm pointing at in real time, that's a fundamentally different way of working through a bug together.

What it does

Synerdio turns any public webpage into a shared debugging session. Inject a tiny script (via bookmarklet or console), create a room, and everyone who joins sees:

  • Live cursors and highlights: Ctrl/Cmd-click an element and the whole room sees it glow, instantly
  • Real performance metrics: TTFB, load timing, memory, long tasks, slow network requests rated in plain language, not just raw numbers
  • Peer-approved temporary patches: propose a CSS/JS fix (with no-code quick actions for common cases, or write it yourself), the room votes, and it applies live for everyone
  • An AI pair that reasons over the room's actual live metrics instead of guessing generically
  • A one-click exportable report to hand off after the session

All of it peer-to-peer over WebRTC, no accounts, no database, no infrastructure to run beyond a static deploy and one small serverless function.

How I built it

The frontend is React 19 + Vite + Tailwind v4. The collaboration layer runs on Trystero, a serverless WebRTC library; rooms are just a shared ID, and peers find each other without me operating any signaling server. The injectable agent is deliberately plain, dependency-free JavaScript, since it has to run safely inside someone else's page.

The one piece that does have a backend is the AI pair: a Vercel serverless function proxies requests to Groq (Llama 3.3 70B), keeping the API key server-side and summarizing the room's live metrics into the prompt so answers are grounded in real data rather than pattern-matched keywords. If that call fails for any reason, it falls back to local heuristics rather than erroring out.

Challenges I ran into

A few of these took real digging to actually root-cause:

  • The bookmarklet silently stopped working. Turned out React 19 blocks javascript: URLs passed through JSX as an XSS precaution, which happens to be the entire mechanism a bookmarklet depends on. Fixed by setting the href imperatively on the raw DOM node, bypassing React's attribute pipeline entirely.
  • Ctrl+click did nothing on Mac. On Mac, Ctrl+click is the OS-level "secondary click" gesture it fires a contextmenu event, not a click. Cmd+click worked fine the whole time; Ctrl+click needed its own listener.
  • The patch-approval quorum could become mathematically unreachable. The vote threshold was originally based on total connected peers, but injected agents have no voting UI and can never vote. With more agents in a room than actual people, the required majority literally couldn't be hit. Fixed by tagging presence with a role and basing quorum only on panel viewers who can actually vote.
  • Votes occasionally vanished. Votes and patch requests travel as separate WebRTC data channels, and Trystero doesn't guarantee any ordering between different channels, only within one. A vote could arrive before the request it belonged to and get silently dropped. I added a small buffer that holds "orphan" votes and replays them once their request shows up.
  • A stored XSS hole in the exported report. Patch CSS/JS comes from peers, potentially untrusted ones and was being interpolated straight into the exported HTML file. Anyone opening that file later could have had arbitrary script run. Fixed with proper HTML-escaping before interpolation.

What I learned

The deepest lesson was that "peer-to-peer" and "consistent" are not the same guarantee WebRTC's ordering promises are per-channel, not global, and any system built on top of it needs to design for messages arriving out of order, not just messages arriving late. I also learned to think about capability, not just connection: "who's in the room" and "who can actually vote" turned out to be genuinely different questions, and conflating them was a real bug, not just an edge case.

On the product side, I learned where to hold the "zero infrastructure" line and where to bend it. The AI pair is meaningfully better with one small serverless function behind it than it would be trying to stay purely client-side, and that's a defensible trade, as long as it's a deliberate one.

What's next

A live time-travel buffer for scrubbing back through a debugging session, and a lightweight drawing/annotation layer alongside the cursors for the moments where even a highlighted element isn't quite enough to say "this, right here."

Built With

Share this project:

Updates