My extension "worked" — it just quietly saved half of every conversation A developer discovered that their browser extension for saving AI chat conversations had a bug that silently dropped half of each conversation—either user questions or AI answers—due to incorrect CSS selectors. After writing a probe script to inspect the actual page structure, they fixed the selectors for Claude and Perplexity, while ChatGPT and Gemini were already working. The developer also found that some images could not be saved due to blob URLs and chose to display an honest message instead of a broken link. My extension had a bug that's the worst kind: it looked like it worked. You'd save a Claude conversation, open it up, and there'd be your questions — every single one of them — and none of Claude's answers. Half the conversation, gone, but neatly. No error, no crash. Just quietly wrong. I want to walk through the day I spent chasing this, because it taught me something I keep having to relearn. Some background. My extension reads AI chat pages — ChatGPT, Claude, Gemini, Perplexity — and pulls the conversation out so you can save it. None of these sites give you an API for that. So you're reading the raw HTML, hunting for the CSS selector that wraps each message. And those selectors are not documented anywhere, because they were never meant for you. They change whenever the site ships a redesign. Here's the mistake I made, more than once: I guessed. I'd think, okay, Claude's assistant messages are probably still .font-claude-message, I remember that from a while back. Ship it. And it'd be wrong, because they'd quietly changed it, and my selector matched exactly zero elements. The user-message selector still worked, so the extension happily grabbed all the user turns and none of the assistant ones. Hence: half a conversation. I guessed for Gemini too. Wrong there as well, just in the opposite direction — I caught the AI answers and dropped the questions. At some point I got tired of being wrong and did the obvious thing I should've done first: I wrote a little probe script. Forty lines. You paste it into the browser console on the actual page, logged into your actual account, and it just tells you the truth — which selectors match, how many elements each one hits, and a snippet of the text inside so you can tell whether it grabbed a real message or the navigation bar. The output was almost funny in how clear it was. For Claude: There it was. Zero. The thing I'd been confidently shipping matched nothing. The real selector for an answer was an attribute I wouldn't have guessed in a hundred years. I ran the probe on all four sites. Twenty minutes of pasting a script into a console did what a week of guessing couldn't. ChatGPT and Gemini turned out to already be fine. Claude and Perplexity were both wrong, in different ways, for different reasons. Then the images. Someone's going to ask "can it save pictures too?" so I looked into it, and this is where it gets humbling. On Gemini, one image in the conversation had a normal https link — fine, savable, might expire but savable. The next image in the same chat was a blob: URL. If you've never run into these: a blob URL is a reference to something sitting in the browser's memory for that one tab, right now. Close the tab and it's gone. There is no version of my extension, or anyone's, that can save that image, because the moment you leave the page the thing it points to stops existing. So I had a choice. Pretend, and save a link that will 100% be a broken image later. Or be honest and write, right there in the saved text, "this image couldn't be saved — go look at the original." I went with honest. A broken image icon is worse than a sentence telling you the truth. Claude does something different again — the uploaded file lives outside the message element entirely, so I can't grab the image, but I can grab the filename. So at least the saved note says "attachment: dog.jpeg" instead of pretending nothing was ever there. A couple of other things broke that day, for the record, because it wasn't only selectors: Here's the thing I keep relearning, and the reason I'm writing this down so I maybe stop forgetting it: I cannot guess what the page looks like. I have a memory of what a selector used to be, and that memory is worse than useless, because it's confident and wrong. The page in front of the user is the only source of truth. A forty-line script that reads that page beats my best guess every single time. Still 0 users, still $0. But the extension now actually saves the whole conversation on all four sites, which it demonstrably did not do this morning. I'll take it. If you build anything that scrapes a page you don't control: write the probe first. Don't be me at 10am. — building NotebookBloom in public, 2