When you build on a product with no public API, you learn fast that "stable API" and "stable data" are two different promises.
I make NotebookBloom (https://notebookbloom.com), a Chrome extension for NotebookLM. One feature imports a whole YouTube playlist as sources, which means talking to YouTube's internal youtubei endpoint. That endpoint has been rock solid — same URL, same continuation-token pagination, hasn't moved in months.
What moves is the JSON it hands back. A field gets renamed. A list nests one level deeper. At one point playlistVideoRenderer quietly became lockupViewModel. The request still succeeds, you get a 200, your parser runs — and silently returns half the playlist. No error. You ship a broken import and hear about it from a user.
My first instinct was to reach for a schema validator like Zod. I didn't, for two reasons:
- It's not my schema. Maintaining a strict validator for a shape I don't own and can't control is a lot of upkeep for something that'll change again next month.
- It only tells me what a broken import already tells me — that something moved — except now I'm carrying an extra dependency to hear it.
So I went the other way. The parser is disposable: one narrow path straight to the field I need, and it throws the moment anything shifts. Loud and empty beats quiet and half-right when the data isn't yours to trust.
Building on someone else's product is 90% this — not clever code, just deciding what to fail on.
If you're curious what the extension actually does, it's here: https://notebookbloom.com (Chrome Web Store: https://chromewebstore.google.com/detail/fmnhogknjhlaicceielblddajjabjlha).
Top comments (0)