The browser extension is supposed to show up on any job posting: LinkedIn, Indeed, Greenhouse, Lever, Ashby. We'd tested it plenty. It worked. Then we sat down and actually visited real, live Greenhouse postings instead of our own test fixtures, and the widget didn't show up at all. Not an error. Not a broken state. Nothing. Silence is a worse bug than a crash, because nobody files a ticket for a feature that simply never appeared.
The widget that vanished
Greenhouse's job pages are a React app, and it turns out they were logging hydration errors on nearly every load, the kind where the server-rendered HTML doesn't match what the client wants to render and React has to recover. We watched it happen with logging turned on: the widget mounts fine, sits in the DOM for about two seconds, then disappears completely. Not hidden. Gone.
The cause was almost funny once we found it. React's recovery from that hydration mismatch was replacing `document.documentElement` outright, swapping in an entirely new `<html>` element rather than patching the existing one. Our widget had a safety net for exactly this kind of disappearance, a MutationObserver watching for the widget getting removed and re-adding it. That safety net was watching the old, now-discarded documentElement. It never fired again. Not because the code was wrong. Because the ground it was standing on got replaced out from under it.
The fix didn't try to out-clever Greenhouse's internals. We added a plain interval that checks every 1.5 seconds whether the widget is still attached to whatever the current documentElement is, and re-adds it if not. Less elegant than a targeted fix. Actually works regardless of what any given site's framework decides to do to its own DOM.
The stage picker that lied
Second one's worse, because it didn't fail loudly. Track a job through the extension and you'd get a stage picker: Wishlist, Applied, Phone Screen, Interview. Click "Phone Screen" and the button lit up like it worked.
It didn't. Our actual default pipeline calls that stage "Screening," not "Phone Screen." The extension's picker was a hardcoded guess that had drifted from what the real app actually uses. When the name you sent didn't match a real stage, the backend quietly fell back to "Applied" instead of erroring. The UI showed you Phone Screen, selected, confirmed. Your board actually said Applied. You'd only find out days later when the pipeline didn't match what you remembered clicking, with nothing pointing you back to why.
The fix: the extension now fetches your actual pipeline stages and renders those, whatever you've named them, including any custom ones you've added yourself. And the backend no longer silently substitutes a stage when a name doesn't match. It errors, clearly, so a mismatch shows up as a mismatch instead of a board that quietly lies to you.
What we'd tell ourselves earlier
Test against the real thing, not your own fixtures. A mocked test page will never reproduce what a live site's own framework does to the DOM out from under you. And never let a UI confirm an action optimistically if there's any chance the backend disagrees. An interface that says "done" when the answer was actually "no" is worse than one that's honest about failing.
