Blog

Writing

Long-form from our team. Engineering, product, and company posts.

  • Product

    A Multilingual Help Center Without Empty Pages

    Kookee's hosted portal used to show every page in the project's default language, whatever the reader picked. Now each language has its own address, a missing translation falls back to the default language, and the language picker lists only the project's languages.

  • Product

    How to Add a Status Page to Your SaaS

    The decisions behind a SaaS status page: what to list, when an uptime monitor should call an outage, how to word incident updates and where the page should live, with the status page and uptime monitors we just added to Kookee as the worked example.

  • Product

    Your Webhooks Shouldn't Trust the URL They Were Given

    A webhook is the one feature where a customer types an address and your servers go and call it. What we built for Kookee's webhooks and its Slack, GitHub and Jira integrations, and eight things a webhook sender has to get right.

  • Product

    Your Help Center Shouldn't Start From a Blank Page

    Most teams already have their help content, in PDFs, Word files and old exports. Retyping it is why help centers stay empty. What we built to import it, and the seven rules that keep an import from feeding secrets to a chatbot.

  • oauth

    Your MCP Server Shouldn't Make People Paste a Token

    Our MCP server worked well with personal tokens, as long as you lived in a terminal. Claude's chat apps and ChatGPT connect by signing in instead. What we shipped so they can, and the seven decisions that took longer than the code.

  • Product

    Your Feedback Widget Shouldn't Make People Sign Up First

    Our feedback board asks for an account, and for votes that is right. For the visitor who just hit a bug and has half a minute, it is a wall. The site widget's new Feedback tab, the five rules we built it by, and why the AI chat is now optional too.

  • Product

    Your Chat Widget Shouldn't Send Visitors Away to Read the Answer

    Our chat cited the right article, and the click on it took the visitor off the page and away from the conversation. We rebuilt the widget around Home, Ask and Help tabs and a reader. The five rules we built it by, and what we left out.

  • headless-cms

    Your CMS's React Components Shouldn't Fetch Their Own Data

    Most headless CMS component kits wrap your app in a provider and fetch inside components. With Server Components that hides content from the first HTML, ships JavaScript for static lists and sends articles twice. The six rules we built ours by.

  • Engineering

    React 19 Rewrites Your dangerouslySetInnerHTML on Every Render

    An inline { __html } object makes React 19 replace an element's whole HTML every time its parent re-renders. We found it through a table of contents stuck on the last heading. Why it happens, what it breaks, and the one-line fix.

  • pagination

    Your Blog Pagination Is Probably Hiding Posts From Google

    Load more buttons, pagination kept in state, every page canonical to page one, noindex on page two: four common ways blog pagination keeps older posts from search engines, what to do instead, and a checklist.

  • security

    Your Invite Link Is a Password You Pasted in Slack

    Send someone an invite link and you have handed out a credential that works for anyone who ever sees it. Here is what that link has to carry before it is safe to paste into a channel, and the decisions behind ours.