When I was setting up analytics for my blog, Google Analytics seemed like the obvious choice. But once I looked at what it actually requires — a tracking script, a cookie consent banner, a cookie policy page, conditional script loading — it felt like way too much for a personal site that doesn't run ads or retargeting.
So I went with Umami instead. It's open-source, self-hosted, and doesn't use cookies by default. For my setup, that means I don't need a consent banner, and my data stays on my own server.
What's Actually Wrong With Google Analytics
Cookies and consent overhead. GA sets first-party tracking cookies (_ga, _ga_<container-id>). Under GDPR, that means you need a proper cookie consent banner with category-by-category opt-in. And users who reject cookies simply won't be tracked — so your data is incomplete from day one.
Your data lives on Google's servers. They process it for their own purposes too. You get a "free" analytics tool, and Google gets visibility into your traffic patterns.
It's heavy and overcomplicated. The GA4 snippet loads around 90–135KB of JavaScript. The dashboard is built for enterprise use cases — overkill if you just want pageviews, referrers, and device stats.
Why Umami
Umami is an open-source, self-hosted analytics platform that gives you the metrics you need without the privacy baggage.
- No cookies — sessions are identified using a hash of IP + user agent + website ID and no raw personal data is stored. That's why I don't show a consent banner on my site.
- Your data, your server — self-hosting on a VPS means no third party ever sees your analytics
- Lightweight — the tracking script is under 2KB (vs GA's 90KB+)
- Clean dashboard — one page with pageviews, unique visitors, bounce rate, session duration, referrers, browsers, OS, devices, and geo data
- Easy to deploy — Docker + PostgreSQL, that's it
How I Set It Up
Here's the Docker Compose config I use:
umami:
image: ghcr.io/umami-software/umami:latest
container_name: umami
environment:
DATABASE_URL: postgresql://umami:${UMAMI_DB_PASSWORD}@umami-db:5432/umami
APP_SECRET: ${UMAMI_APP_SECRET}
TWO_FACTOR_ENCRYPTION_KEY: ${UMAMI_2FA_KEY}
depends_on:
umami-db:
condition: service_healthy
init: true
restart: always
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat"]
interval: 5s
timeout: 5s
retries: 5
umami-db:
image: postgres:16-alpine
container_name: umami-db
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: ${UMAMI_DB_PASSWORD}
volumes:
- umami-db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U umami"]
interval: 5s
timeout: 5s
retries: 5
restart: always
After docker compose up -d:
- Log in at port 3000 with
admin/umami, change the password immediately - Go to Settings → Websites → Add website
- Copy the tracking script into your site's
<head>
In Next.js I use the Script component:
import Script from 'next/script';
<Script
defer
src="https://your-umami-instance.com/script.js"
data-website-id="your-website-id"
strategy="afterInteractive"
/>
No Cookie Banner, By Design
With Google Analytics I would have needed to build consent UI that loads before tracking, implement granular consent categories, write a cookie policy, and add conditional script loading. All of that for a personal blog.
With Umami in its default configuration, the script just loads, and I don't show a banner. Nobody has to click through a consent popup, so the UX is cleaner and the data is more complete. (This is my own assessment, not legal advice. Rules vary by country, so check what applies to you.)
What You Give Up
To be fair, there are trade-offs:
- No cross-site tracking — you can't follow users across domains or build retargeting audiences
- No Google Ads integration — if you run paid campaigns, you'll need GA for conversion attribution
- Simpler event tracking — Umami's custom events don't have GA4-level granularity for complex funnels
- Self-hosting maintenance — you're responsible for updates and database backups (minimal, but it's there)
For a blog or portfolio, none of these matter. You're not retargeting visitors or running ad funnels.
GA vs Umami at a Glance
| Feature | Google Analytics | Umami |
|---|---|---|
| Cookies | Yes (_ga, _ga_<id>) |
None |
| Cookie banner required | Yes (GDPR) | No |
| Data location | Google's servers | Your server |
| Script size | ~90KB+ | <2KB |
| Self-hostable | No | Yes |
| Price | Free (data as payment) | Free (open source) |
| Setup complexity | Moderate | Low (Docker) |
| Dashboard | Complex, enterprise-focused | Simple, one-page |
| Cross-site tracking | Yes | No |
| Ad integration | Yes | No |
Bottom Line
If you're running a personal site, blog, or small project — think about whether you actually need Google Analytics. Umami gives you everything that matters (who visits, where they come from, what they read) without the privacy infrastructure overhead. Setup takes about fifteen minutes if you already have Docker running. If you enable extra features or add other scripts, re-check whether you need consent.
Top comments (3)
the self-hosting maintenance point is the one people underestimate. running postgres for analytics is easy until it isn't: backups, updates, the odd disk-full at 3am. i self-host a few things and that trade-off is exactly why i didn't self-host analytics for my own site either.
the trade-off list is honest though, especially the events one. umami's custom events feel basic if you're used to ga4 funnels, and it's good that you said it instead of pretending nothing was lost.
Totally agree. Most of us who self-host have been through this already. Regular backups and log/file rotation save a lot of disk space and a lot of headaches. And it's much better to test the whole setup, including restoring from a backup, before it goes to production.
the restore test is the part everyone skips. i've met plenty of people with pristine backup schedules and zero successful restores, which means the backup exists but the recovery doesn't.