Your site can keep the comments
July 12, 2026
The last post about this described the arrangement: this blog has no comment system, and posts that want a discussion link to a thread on Popsicle Boat instead. One anchor tag, nothing loaded in your browser, conversation happens somewhere built for conversations.
There was one honest objection to that design, and I eventually made it to myself: the link sends readers away. The conversation about a post ends up living somewhere other than the post. For a comment section, that’s backwards — you should be able to read the comments where you read the thing they’re about.
We tried solving this once before with an embed — an iframe mirroring the thread onto the page — and buried it, for reasons that still hold: an embed is one more thing a reader’s browser has to trust, and replies written for a community read strangely when beamed somewhere else live. The problem with the embed wasn’t the where. It was the when.
Build time, not run time #
Every thread on the boat now publishes its public replies as plain JSON — the thread’s address plus /replies.json:
{
"thread": {
"title": "The panel that closed itself",
"url": "https://www.popsicleboat.com/c/blogging/posts/175",
"reply_count": 1
},
"replies": [
{
"author": "jake",
"body_html": "<p>Test</p>",
"posted_at": "2026-07-12T23:53:45Z",
"url": "https://www.popsicleboat.com/c/blogging/posts/175#reply-176"
}
]
}
A static site fetches that while it builds and prints the conversation into the page as ordinary HTML. This blog’s Hugo template does it in about ten lines:
{{ with try (resources.GetRemote (printf "%s/replies.json" .Params.popsicleboat)) }}
{{ if and (not .Err) .Value }}
{{ $replies := .Value.Content | transform.Unmarshal }}
{{ range $replies.replies }}
<article class="boat-reply">
<p><strong>{{ .author }}</strong> · <a href="{{ .url }}">{{ dateFormat "January 2, 2006" (time .posted_at) }}</a></p>
{{ .body_html | safeHTML }}
</article>
{{ end }}
{{ end }}
{{ end }}
No script. No iframe. Nothing for a content blocker to block, because there is nothing running. The replies you may be reading below this very post arrived that way — view source; it’s just paragraphs.
What this actually changes #
Reading happens at home. The blog is where the conversation is read; the boat is where it happens. Readers who just want to see what people said never leave your page. Readers who want to say something click through to a place with names and norms.
And the no-lock-in promise stops being a promise and becomes a property of the files. Every build, your site writes its own copy of every conversation. If the boat sank tomorrow — or if you simply left — the comments would still be right there in your HTML, yours, forever. A comment service where leaving costs nothing and takes nothing with it is, as far as I know, a new kind of deal.
Fresh replies appear on your next build. Static sites rebuild all the time; the conversation is never staler than your deploy habit, and the live thread is one click away regardless.
The comments came home. The conversation kept its address.