Three games, three domains, three analytics instances. Then I did the maths.
At some point between CocktailGuessr and a spreadsheet of renewal costs, the architecture stopped making sense.
By the time CocktailGuessr launched, I had three separate games on three separate domains with three separate analytics setups. It worked fine. Then I sat down and did the maths on what adding five more games would cost.
``` dailyguessr.app $11/yr flagguessr.app $15/yr cocktailguessr.app $15/yr stoop.games $27/yr (hub, already bought) ───────────────────── Current total ~$68/yr
Adding 5 more games at $15 each: ~$143/yr ```
Not ruinous. But unnecessary. And the analytics situation was worse.
The analytics problem
Each game started on Umami Cloud — a hosted analytics service, privacy-friendly, cookieless. The free tier covers three websites. I had three games. That worked for exactly one week before I started planning the fourth game.
The paid tier was $9/month. That's $108/year just to count page views. For a free hobby project with no revenue yet, that felt wrong.
The alternative: self-host Umami. It's open source. You run it on your own server, you get unlimited websites, you pay only for the server — which on Railway's free trial is zero, and on the Hobby plan is roughly $2/month.
I'd never self-hosted anything.
Railway at midnight
The setup wasn't technically hard — Railway has a one-click Umami template, you click Deploy, it provisions Postgres and the app automatically. The hard part was DNS.
To give Umami a real domain (analytics.stoop.games) I needed to add a CNAME record in Porkbun, tell Railway to use that domain, then wait for propagation.
DNS propagation has a TTL — a "time to live" that says how long the old record should be cached. Mine was set to 600 seconds. Ten minutes. In theory.
In practice, I spent an hour staring at ERR_NAME_NOT_RESOLVED in Chrome's DevTools after the ten minutes had long passed. The record existed. Railway said it was connected. The browser disagreed.
The fix was ipconfig /flushdns in PowerShell — clearing the local DNS cache Chrome was still reading from. After that it worked immediately.
This is the kind of problem that has nothing to do with building a game. You learn it once and never forget it.
The stoop.games decision
Both problems pointed at the same answer: I needed a hub.
stoop.games would be the landing page — a place to see all the games, understand what Stoop is, and land if you followed a link from anywhere. The guessing games kept their own domains because they had real SEO value. The arcade games I was planning — Palette, Bloom, Sortl — would live as subdomains: palette.stoop.games. Free, no renewal cost, consistent branding.
The revised cost projection:
`` Own domains (guessing games): ~$60/yr stoop.games hub: $27/yr Arcade subdomains: $0 Railway (Umami): ~$24/yr ──────────────────────────────────── Total for 8 games: ~$111/yr ``
Versus ~$143+ with everything on separate domains. The architecture is also cleaner, and cleaner architecture compounds.
One dashboard for everything
The moment I got self-hosted Umami running and added all six games as separate websites in one dashboard — all tracked, all visible, all free — felt genuinely satisfying.
Not because of the money saved. Because the system made sense. One server, one URL, one login, everything in one place.
The Palette analytics bug that ate an afternoon? Caused by the wrong subdomain in the script tag — umami.stoop.games instead of analytics.stoop.games. A typo from the transition period. It didn't surface until Palette launched and showed zero data for two days. Small price for a cleaner system going forward.