personal-presence-os

Measure before you build

  • shipped
  • analytics
  • goatcounter
  • infrastructure

The temptation

The engine can render pages, serve them across five domains, and produce rich previews when links are shared. The natural next step feels like engagement: add a newsletter signup, comments, a community space. Start talking to people.

But talking to whom? I have no idea whether anyone is reading these pages. The sites have been live for a few days. There might be ten visitors. There might be zero. Without that number, every engagement feature is a guess — and guesses cost time.

The instinct to build engagement before measuring traffic is the same instinct that makes people buy business cards before they have customers. It feels productive. It's not.

What I actually need first

Before newsletters or comments, I need to answer three questions:

  1. Is anyone visiting at all? If no one is coming, the problem isn't engagement — it's distribution.
  2. What are they reading? If one article gets 90% of traffic, that tells me what to write more of.
  3. Where did they come from? Referrer data shows whether traffic is organic, from social shares, or from AI assistants citing my content (which is the whole hypothesis behind this engine).

These are analytics questions, not engagement questions. You measure before you build.

Why self-hosted

The budget for this entire project is $6/month. That buys a VPS and a domain. There is no room for a $9/month analytics service, and there's no appetite for sending visitor data to a third party when the whole project is about owning your presence.

I looked at everything: Plausible (too heavy — needs PostgreSQL and ClickHouse, would eat half my server's RAM), Umami (still needs PostgreSQL), Cloudflare Analytics (free but shallow — no per-path data, no API).

GoatCounter is a single Go binary that stores data in SQLite. It uses about 50 MB of RAM. It doesn't set cookies. It has a dashboard and an API. It costs nothing. I downloaded it, created a systemd service, pointed a subdomain at it through the engine's reverse proxy, and it was running in twenty minutes.

The full setup is documented in the analytics setup guide.

How it works across all domains

The engine injects a GoatCounter tracking script into every page at build time — all five domains, every page type. The script points to stats.kda.zone, which the engine proxies to GoatCounter on localhost. No new services needed. No firewall changes. The engine already routes by Host header; this is just one more hostname.

GoatCounter sees the full URL including the domain, so traffic from wardleymaps.com and agency.kda.zone shows up as distinct in the dashboard. One installation, five domains, complete visibility.

What's next

Once I have a week or two of data, I'll know whether to invest in engagement features or in distribution. If people are visiting but not coming back, that's a newsletter problem. If nobody is visiting, that's a content and distribution problem. If traffic comes from AI assistants, the core hypothesis is working and I need to double down on structured content.

The data will tell me what to build next. That's the point.