#71 Entitlements are easy (until they’re not)

Early-stage products are all about uncertainty. With poketto.me, I started by building something I wanted to use — and gave it away for free. Then came early adopters asking for features, and eventually I began experimenting with monetizable “premium” features: personalized podcasts, news aggregation, summaries, contextualization, etc. That third bucket quickly gave me headaches. I needed a way to put usage guardrails around these features: 👉 to separate free from premium, 👉 to distinguish “beta” from production-ready, 👉 and to keep my future monetization options open. ...

September 9, 2025

#70 A room without a dustbin will never be clean

This is a roundabout way of saying: make “good” behavior the easy choice. But there’s an interesting backstory to the saying. I come from a family of manual laborers. My dad, all of my uncles, and most of my many cousins work in trades ranging from carpentry to plumbing to house painting. And one of the first things any good craftsman does when setting up at a new site? Installing a dustbin. ...

September 8, 2025

#69 Debugging your Stripe integration is easy with Stripe CLI

I put off building checkout and payments for the premium version of poketto.me for way too long. The thought of integrating with Stripe — keeping “their” and “my” data in sync, handling callbacks, connecting the UI, smoothing out user flows… it always felt like too much to tackle on any given day. But once I committed to a GA date for the premium version, I had to bite the bullet. ...

September 7, 2025

#68 Product analytics? PostHog is my tool of choice!

Event tracking and analytics is one of those cross-cutting topics I mentioned back in You don’t need to bring out the big guns right away (but it’s good to know them anyway): in the beginning, it doesn’t really matter if or how you do it. Often, you can just hack something together and move on to more important things. For the longest time, for example, poketto.me just had a hard-coded email notification that let me know whenever a new user signed up. That was enough to give me a general sense of what was going on. ...

September 6, 2025

#66 Your browser extension doesn’t necessarily need that many permissions

The other week, I was building a neat little feature for the poketto.me browser extensions (Chrome, Firefox, and Edge): when you save a web page, the extension should capture not just the URL, but the entire content you’re looking at in that moment. 🤨Why does this matter? If you’re signed in on a page (say, with your New York Times subscription), poketto.me can capture the full article — just as you, the paying subscriber, see it. Otherwise, poketto.me tries to fetch the article in the background… but it will run straight into the paywall (see TIL #59). ...

September 4, 2025

#64 Always suspect your own code first

I physically winced when a beta tester of the poketto.me Android app reported this bug: “Sometimes, adding new tags to a Save doesn’t work. I open the tagging dialog, type a new tag, click ‘save’ — the input field clears, but the new tag is nowhere to be seen.” I was able to reproduce the issue on my phone and in an Android emulator. Gut reaction: “Ah, must be the WebView. WebViews always behave differently than a normal browser. This will be a mess.” ...

September 2, 2025

#63 Social media “previews” are tricky (part 2)

Yesterday, I described my elegant solution to the social media “preview” problem: Direct the share URL to the Python backend, render a skeleton HTML page with machine-readable metadata, and send real browsers to the Angular app’s proper “read” page. But… how exactly do you redirect the user? My first, naive idea was to use the age-old HTML redirect tag: <meta http-equiv="refresh" content="0; url=http://example.com/" \> My assumption: social media bots wouldn’t follow these “semantic” redirects, but they would follow HTTP redirects (which they definitely do). This worked perfectly — except for LinkedIn 😅 ...

September 1, 2025

#62 Social media “previews” are tricky (part 1)

When you add a link to a website to post on Bluesky, Facebook, or LinkedIn, your post will often contain a “preview” of the target page. That’s great — it makes the post more appealing and more likely to get clicks. But how do social media platforms fetch the exact content they embed in that preview? That’s… a tiny rabbit hole. Enter: the “Share…” feature of poketto.me. You can share any saved content with others via poketto.me. Anyone who opens the link gets the same distraction-free reading experience, whether or not they use poketto.me. ...

August 31, 2025

#61 Firefox and Chrome (finally!) support the same extension API (and so does Microsoft Edge)

I hadn’t actually planned to build a Firefox extension for poketto.me. But among the first wave of “Pocket Converts” — users who turned to poketto.me after reading about it as an alternative to Pocket — several asked for a Firefox extension. So, I decided to do a quick technical feasibility check. As it turns out: The Chrome extension works in Firefox without a single code change! Apparently, there are a few APIs that Firefox doesn’t support (see: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Browser_support_for_JavaScript_APIs), but luckily, I didn’t rely on any of those. ...

August 30, 2025

#60 Don’t generalize too soon. But do generalize.

It’s generally good practice among developers to break things down into small, independent, reusable components. But, like all good things, it can become problematic when taken too far too soon. Here’s an example from poketto.me: A few weeks ago, I introduced colored tags. Users can choose one of eight colors for each tag to help them quickly find what they’re looking for and organize their tags visually. (Personally, I use one color for all location-related tags, another for tech topics, etc.) ...

August 29, 2025