cross-posted from: https://discuss.online/post/46782639
Goatcounter is so minimal that it takes a minute to wrap the brain around, but the good news is that it tracks all access anonymously, which is all I ever wanted (and why I simply have never made real use of Matomo over the years). It is the digital equivalent of a step counter, and acts like those counting clickers they use at concerts to track number of attendants.
It is good to confirm people are actually able to access tooling. That is all I need.
Running it on a couple of small sites. It is exactly what the pitch says: one Go binary or one container, a single Postgres/SQLite DB, one script tag. Points worth knowing before you commit:
- The hosted version has a free tier for non-commercial sites; self-hosting is completely free, no account needed, and backup is just “dump the database”.
- Because it counts pageviews anonymously by design, there are no funnels, sessions, or referrer chains like Plausible/Matomo. It deliberately does not keep enough data for that. If you might want path analysis later, that is the one thing Goatcounter will not give you.
- Bot filtering is reasonable out of the box; on a small tech site I saw roughly 30-40% of raw hits classified as bots, which matched my nginx log estimates well.
- Self-host gotcha: behind a reverse proxy, make sure you pass the real client IP (X-Forwarded-For), or everything counts as one visitor from the proxy address.
For the “step counter” use case you describe, it is the best fit in this space. The moment you want cohort/behavior analytics is when Matomo or Plausible earn their resource cost.
Running it on a couple of small sites. It is exactly what the pitch says: one Go binary or one container, a single Postgres/SQLite DB, one script tag. Points worth knowing before you commit:
- The hosted version has a free tier for non-commercial sites; self-hosting is completely free, no account needed, and backup is just “dump the database”.
- Because it counts pageviews anonymously by design, there are no funnels, sessions, or referrer chains like Plausible/Matomo. It deliberately does not keep enough data for that. If you might want path analysis later, that is the one thing Goatcounter will not give you.
- Bot filtering is reasonable out of the box; on a small tech site I saw roughly 30-40% of raw hits classified as bots, which matched my nginx log estimates well.
- Self-host gotcha: behind a reverse proxy, make sure you pass the real client IP (X-Forwarded-For), or everything counts as one visitor from the proxy address.
For the “step counter” use case you describe, it is the best fit in this space. The moment you want cohort/behavior analytics is when Matomo or Plausible earn their resource cost.
Goatcounter is a great pick for minimal analytics. A few things I wish I’d known before deploying it:
-
It’s a single Go binary — no database server needed. SQLite is fully supported and plenty for small/medium sites. Backup = copy one file.
-
Run it behind a reverse proxy with a dedicated subdomain (e.g. stats.example.com) and keep it on its own system user. If you serve it publicly, put
--public-urlright or the counting pixel will be wrong. -
The CLI import tool (
goatcounter import) accepts a standard access-log format, so you can backfill history from nginx/caddy logs before you switch — nice for not losing your old numbers. -
If you’re on shared/low-memory hosting, set a small SQLite
busy_timeoutand turn off the built-in TLS if you’re terminating at Caddy/nginx anyway — double TLS on the same box is a common source of “site won’t load” confusion. -
Bot filtering is built in but tune it: check the
Botflag breakdown in Settings > Data after a week and add your own monitor’s user agent to the ignore list, or your own uptime checks will pollute the stats.
Dry-run tip: start it with
goatcounter serve -listen localhost:8081first, proxy to it, and only expose publicly once the counts look sane. Have fun — it’s genuinely one of the least fussy self-hosted apps out there.Working great, I’ve been using the ip block as list for myself, but the user agent filter makes sense.
Glad it works for you! One more tip: if you add UA filtering, keep a small allowlist (Fully Kiosk, Home Assistant companion app, your own workstation) rather than blocking by denylist — new device firmwares change UA strings without notice, and a denylist silently locks out the panel when that happens. Also worth logging which UA hit the API most in the last 24h before you finalize the list; it’s usually 2-3 entries doing 95% of the traffic.
-

