Privacy-First Analytics: Self-Hosted, Simple, Smart

Taming Web Analytics: Building a Privacy-First Analytics Stack
The borisovai-admin project needed proper web analytics—the kind that doesn’t require a lengthy privacy policy or a consent banner that annoys users. Our goal was crystal clear: integrate a self-hosted analytics solution that respects visitor privacy while giving us real insights into how people use our platform.
The Discovery Phase
After evaluating the usual suspects, I landed on Umami Analytics. Not the standard version, but a clever SQLite fork by the community (maxime-j/umami-sqlite) that lets us run the entire analytics engine in a single Docker container instead of juggling multiple services. That decision alone saved us roughly 100 MB of RAM and eliminated a whole layer of orchestration complexity.
Building It Out in Four Phases
First came the Docker setup. I created an idempotent installation script—seven steps that you can run repeatedly without breaking anything. The beauty of idempotency is that you can execute it during CI/CD without fear. SQLite lives in a Docker volume, so data persists across container restarts.
The CI/CD integration came next. Two new jobs in our pipeline: one that provisions Docker (if it’s not already there) and another that installs Umami automatically. The icing on the cake? An incremental deployment script that checks the service health before considering the job complete. No more guessing whether your analytics stack is actually running.
Then I built a management UI—a simple analytics.html page where team members can grab the integration code they need to add tracking to their apps. It’s paired with a /api/analytics/status endpoint, giving us programmatic access to the service state.
The Educational Bit: Why SQLite for Analytics?
Here’s what’s counterintuitive: SQLite in containers works surprisingly well for moderate analytics loads. Traditionally, people assume you need PostgreSQL or MySQL for any serious data work. But SQLite has become genuinely competent for analytics workloads. It eliminates network overhead, reduces operational complexity, and when combined with Docker volumes, gives you durability. The tradeoff is concurrent writes—SQLite serializes them—but for analytics, most traffic is reads anyway.
Privacy By Design
The privacy angle was non-negotiable. Umami doesn’t use cookies, making it GDPR-compliant out of the box. No consent banners needed. The tracking script itself is tiny (around 2 KB) and loads asynchronously, so it never blocks your page rendering. I even configured it with a custom tracker script name (stats) to bypass common ad blockers—a pragmatic choice for actually getting data.
What Got Documented
I updated our internal documentation with AGENT_ANALYTICS.md for the team and a service table in CLAUDE.md listing all our infrastructure components. Everything’s routed through Traefik with HTTPS termination, available at analytics.borisovai.ru and analytics.borisovai.tech.
The Outcome
We now have a privacy-respecting, self-hosted analytics platform that requires minimal operational overhead. The next developer can spin it up in seconds, the monitoring is built into the pipeline, and our users get tracked without the usual dark-pattern nonsense.
Documentation is like sex: when it’s good, it’s very good. When it’s bad, it’s better than nothing.
Metadata
- Branch:
- main
- Dev Joke
- ArgoCD — как первая любовь: никогда не забудешь, но возвращаться не стоит.