#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

#58 The occasional toast can’t hurt

Some of the designers and frontend devs I’ve worked with may remember my rants against toast notifications: “Why do I need a success message for every action? I expect things to work. Only tell me when something breaks.” But… I’ll admit it: Sometimes toasts do have their merit. Two examples from poketto.me: 🔹 Copy to clipboard (Podcast feed URL): When users click the “copy” button, the action happens instantly. But without any feedback, it feels… awkward. ...

August 27, 2025

#57 Multi-threaded TTS: A bad idea

Running text-to-speech in the cloud is fun—until it isn’t. Early on, I didn’t think much about thread safety. During my own testing, rarely would more than one TTS task be running in parallel, so there were no big issues. But once more users started using the feature, strange bugs popped up: Errors like “Assertion srcIndex < srcSelectDimSize failed” started showing up in the logs—and worse, once triggered, the entire Cloud Run instance would become unusable until a redeploy. ...

August 26, 2025

#52 Object.assign(...) in JavaScript helps with asynchronous updates

In WebSockets: More than tech vanity, I talked about the implicit user value of asynchronous UIs. Today, here’s a neat little JavaScript trick I hadn’t been aware of that makes implementing them a bit easier: Object.assign(...). Here’s the situation: Your Angular frontend initially fetches a list of items from the backend. Thanks to Angular’s powerful data binding, many components reference properties of these objects. Later, the backend sends an updated version of one of these items via WebSocket. What now? ...

August 21, 2025