Cookieless Tracking 2026: 5 Self-Hosted Setups (No Consent Banner)
Two numbers. 5 — the number of EU DPAs that have ruled GA4 deployments non-compliant since 2022 (Italy Garante, Austria DSB, France CNIL, Denmark Datatilsynet, Finland Tietosuoja). All five issued remediation orders, not headline fines — but a sixth ruling, or the next CNIL formal notice that escalates, is your next compliance audit. 25-45% — the typical ad-blocker rate in tech-savvy EU audiences, which is data you’ve already been losing without seeing the missing rows. Self-hosted cookieless analytics on a €4.51/mo Hetzner CX22 fixes both: zero compliance exposure, zero ad-blocker drop-off, and €1,200-3,500/yr saved over a Cloud-hosted privacy tool. The trade-off — what you give up — is the subject of this guide.
This guide ships 5 self-hosted cookieless recipes covering Plausible, Matomo, Umami, PostHog, and GoatCounter — each with the install command, GDPR posture, ad-blocker bypass, and an honest “what you lose” section. Plus a 5-tool decision matrix, a “when cookieless is the wrong answer” anti-pattern, and 6 production pitfalls. New to self-hosted analytics? Start with the broader landscape in the 10 self-hosted GA alternatives hero pillar; this article is the cookieless deep-dive on top of it.
What “cookieless” actually means in 2026
“Cookieless” has three definitions floating around. Two of them are marketing; one is the one regulators care about.
- No third-party cookies. Browser already enforces this since Safari ITP (2017), Brave (default), and Firefox Total Cookie Protection. GA4 still falls into this bucket because its first-party
_gacookie is set on your domain. Useless as a privacy claim. - No client-side persistent storage at all. No cookies, no localStorage, no IndexedDB, no fingerprinting beyond an ephemeral session bucket. This is the standard the EDPB and CNIL apply to qualify for the “anonymous audience measurement” exemption (no consent banner required).
- “Cookieless” via Google’s Consent Mode v2. Sends modeled signals when consent is denied. Underlying request still attempts a cookie. EU regulators have not accepted this as equivalent to no-cookie analytics.
The shape that qualifies for the EU exemption is the second one: an opaque server-side identifier with no client persistence and no PII at rest. Plausible, Matomo (with disableCookies), Umami, and GoatCounter all implement variants of this pattern. PostHog defaults to localStorage, which crosses the line under stricter DPA interpretations — we’ll cover the memory-only mode that fixes that.
Why it matters in 2026
Five years of CNIL formal notices, the DPC Ireland €1.2 bn ruling against Meta over EU-US transfers (May 2023), and the Schrems II judgment (Case C-311/18) against US data transfers under FISA 702 mean GA4 + Consent Mode v2 is not a settled question. Italy (Garante 2022, Caffeina Media), Austria (DSB 2021/2022, NetDoktor), France (CNIL 2022 + 2024), Denmark (Datatilsynet 2022), and Finland (Tietosuoja 2024) have all ruled GA4 deployments non-compliant in specific configurations — orders, not headline fines, but the next escalation is the question.
Add the data side: ad-blockers strip /google-analytics.com/collect at ~28% in mainstream EU audiences and 38-45% in tech verticals (per EasyPrivacy filter list coverage and Plausible’s published telemetry). Cookie banner reject-all rates run 40-60% in B2C. Stack the losses and your “97% data accuracy” GA4 dashboard is fiction — you just don’t see the missing rows. Self-hosted cookieless on a first-party domain bypasses both.
When cookieless is the wrong answer
Pre-disqualify before reading 5 recipes. If any of these describe your job-to-be-done, cookieless analytics will fight you the whole way:
- Authenticated SaaS with cohort retention requirements. You need persistent cross-day identity for engagement metrics, retention curves, and paid-feature attribution. Cookieless 24-hour windows make this impossible without an opaque server-issued ID (which, unlike hashed email, is GDPR-acceptable but requires application-level work).
- Paid acquisition where ROAS attribution matters. If you’re spending on Google Ads or Meta and need full-funnel ROI, you need conversion-stitching across sessions and devices. Cookieless can’t do that. Run a server-side conversion API alongside (Conversions API for Meta, Enhanced Conversions for Google) and accept the reduced fidelity.
- Fraud or abuse detection. You need to identify the same actor across days/IPs/devices. That’s the opposite of what cookieless tools are designed for. Use a dedicated fraud-detection layer (Cloudflare Turnstile + your own risk service), not analytics.
- You operate under a DPA contract that requires explicit consent for any analytics. Some German DSK 2021 readings treat localStorage and even URL-based identifiers as equivalent to cookies. If your contract specifies “no analytics without consent,” you need a banner regardless of the tool.
If those don’t apply — and for ~80% of marketing sites, blogs, indie SaaS, and EU e-commerce, they don’t — pick a recipe below.
Ad-blocker bypass: shared pattern for all five tools
Every tool below is on at least one ad-blocker filter list. uBlock Origin matches plausible.io, matomo.php, umami.is, posthog.com, and goatcounter.com by default through EasyPrivacy. Self-hosting on your own subdomain is necessary but not sufficient — the script URL must also be relative or first-party. The shared fix is a reverse-proxy block on your storefront origin:
# nginx — add to your site's server block
# Pattern: proxy /js/.js + /api/ through your apex domain
location ~ ^/js/(plausible|matomo|umami|posthog)\.js$ {
proxy_pass https://analytics.example.com$request_uri;
proxy_set_header Host analytics.example.com;
proxy_cache_valid 200 6h;
proxy_set_header Accept-Encoding "";
}
location ~ ^/api/(event|matomo\.php|umami|posthog)$ {
proxy_pass https://analytics.example.com$request_uri;
proxy_set_header Host analytics.example.com;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
Block-rate before this fix: ~28% in EU mainstream, ~38-45% in tech audiences. Block-rate after: typically <3% (only the most aggressive Brave + uBlock + NextDNS triple-stack still catches your apex domain).
Recipe 1: Plausible Community Edition
The default safe choice for EU marketing sites and blogs. Three Docker containers (Plausible app + PostgreSQL + ClickHouse). No cookies. Per Plausible’s data policy + ingestion source (lib/plausible/ingestion/event.ex): visitor IDs are SipHash.hash(salt_key, UA + IP + domain + root_domain) — the daily-rotating salt is the SipHash key (not concatenated), and a two-salt window (current + previous) preserves in-flight sessions across midnight rotation.
Tracking script
<!-- Variants are pre-compiled with ALPHABETICAL segment order.
Get the order wrong and the file 404s. -->
<script defer
data-domain="example.com"
src="https://analytics.example.com/js/script.file-downloads.outbound-links.revenue.js"></script>
<script>
window.plausible = window.plausible || function() {
(window.plausible.q = window.plausible.q || []).push(arguments)
};
</script>
Server-side privacy settings
Plausible CE ships zero cookies and salt-rotation by default — nothing to configure. The salt rotates daily at 00:00 UTC via Oban cron (config/runtime.exs); ingestion holds two salts (current + previous, ~48h window) so a session that started 23h59m ago doesn’t suddenly disappear at midnight. For event ingestion endpoint requirements (mandatory headers, debug surfaces), see the Plausible custom events deep-dive.
Cost & when to pick
- Cost: €4.51/mo Hetzner CX22 (4 GB RAM, 2 vCPU, EU) + €0 software
- Pick when: EU marketing site / blog / SaaS landing page; you want a clean Google-Analytics-shaped UI without GA’s legal exposure; team is non-technical and needs the dashboard to look familiar
- What you give up: cross-day funnels via
user_id(24h salt window), advanced segment-builders, session replay, heatmaps
Full Hetzner deploy: Plausible CE on Hetzner: 20-minute setup. Once installed, the events + revenue + funnel SQL deep-dive covers Stripe webhooks, ClickHouse queries, and refund handling.
Recipe 2: Matomo with cookies disabled
The GA-parity choice: heatmaps, session recordings, A/B testing, ecommerce, custom reports, all on your own MariaDB. The cookieless mode requires explicit configuration — Matomo defaults to first-party cookies; you turn them off via _paq calls and admin settings.
Tracking script (cookieless mode)
<script>
var _paq = window._paq = window._paq || [];
_paq.push(['disableCookies']); // mandatory: no _pk_id, no _pk_ses
_paq.push(['setDoNotTrack', true]); // honor DNT
_paq.push(['disableBrowserFeatureDetection']); // less fingerprinting; reduces visitor dedup accuracy
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u = 'https://analytics.example.com/';
_paq.push(['setTrackerUrl', u + 'matomo.php']);
_paq.push(['setSiteId', '1']);
var d = document, g = d.createElement('script');
g.async = true; g.src = u + 'matomo.js';
d.getElementsByTagName('script')[0].parentNode.insertBefore(g, d.getElementsByTagName('script')[0]);
})();
</script>
Server-side privacy settings
In the admin UI: Privacy → Anonymize Visitors’ IPs → mask 2 bytes (or 3 bytes for the strictest CNIL-aligned posture; both are accepted under the CNIL audience-measurement exemption guidance). Then System → General → Tracker → Use third-party cookies: OFF and Privacy → Settings → Exclude Bots: ON.
Cost & when to pick
- Cost: €4.51/mo Hetzner CX22 (Matomo + MariaDB on same box, comfortable up to ~5M events/mo)
- Pick when: need GA-parity reports + Goals + Ecommerce + funnels + heatmaps + session replay; willing to run MariaDB; want CNIL configuration guide alignment
- What you give up: setup complexity (vs Plausible/Umami), heavier infra than Plausible, less polished cookieless dev-experience (admin sets matter)
Full deploy: Matomo on Hetzner with MariaDB and Caddy. Ecommerce specifics (WooCommerce + Shopify): Matomo Ecommerce Tracking deep-dive.
Recipe 3: Umami v2
The fastest cookieless deploy in this list. Umami writes zero cookies, zero localStorage by default and runs as a single Next.js app + PostgreSQL backend. No flags to configure, no disableCookies call. Runs free on Vercel + Neon up to ~100k events/mo.
Tracking script
<!-- Default: tracker fetches from your Umami host
data-website-id is a UUID generated when you create the site -->
<script async
defer
data-website-id="abc-123-uuid"
data-host-url="https://analytics.example.com"
src="https://analytics.example.com/script.js"></script>
For custom events, Umami v2 uses declarative HTML attributes (no _paq queue):
<button data-umami-event="signup-cta"
data-umami-event-plan="pro"
data-umami-event-source="hero">
Sign up
</button>
<!-- Or programmatically -->
<script>
if (window.umami) umami.track('Purchase', { plan: 'pro', amount: 49 });
</script>
Privacy posture
Per Umami source (src/app/api/send/route.ts): visitor identification is SHA-512(website_id + IP + User-Agent + APP_SECRET + salt) → UUIDv5, stored only as the UUID. Salt rotation default is monthly (SALT_ROTATION='month'); set SALT_ROTATION=day in env to match Plausible’s daily cadence, =week for weekly. No cookies, no localStorage, no IndexedDB. Umami doesn’t ship a privacy-policy template — write your own. Multi-site is a v2 feature: one PostgreSQL serves N sites via data-website-id routing.
Cost & when to pick
- Cost: €0/mo on Vercel Hobby + Neon free tier (good to ~100k events/mo); €4.51/mo Hetzner CX22 if you outgrow free tiers
- Pick when: single marketing site or blog; want the simplest possible deploy; OK with thinner reporting (no funnels, no session replay, no goals UI — events only)
- What you give up: funnels, cohort analysis, heatmaps. The trade-off for the simplest install.
Full free-tier deploy: Umami on Vercel + Neon.
Recipe 4: PostHog in memory mode
The product-analytics choice: feature flags, A/B tests, session replay, funnels, retention curves. PostHog defaults to localStorage+cookie persistence (cross-day identity), which under stricter EU readings (German DSK 2021, Spanish AEPD) is treated equivalent to cookies under ePrivacy. The persistence: 'memory' mode fixes this but trades off everything PostHog is good at.
Tracking script (memory mode)
<script>
!function(t,e){...}(document,window); // standard PostHog snippet
posthog.init('phc_YOUR_KEY', {
api_host: 'https://analytics.example.com',
persistence: 'memory', // no cookies, no localStorage
autocapture: false, // memory mode = new distinct_id every page; autocapture floods events
disable_session_recording: true, // session replay needs persistence
capture_pageview: true,
});
</script>
Persistence trade-offs
| Mode | Cookies | localStorage | Cross-day identity | Session replay | EU consent-banner-free? |
|---|---|---|---|---|---|
localStorage+cookie (default) | Yes | Yes | Yes (months) | Yes | No (consent required) |
localStorage | No | Yes | Yes | Yes | Borderline (DSK 2021 says no) |
memory | No | No | No (page reload = new ID) | No | Yes |
Cost & when to pick
- Cost: €12-20/mo on Hetzner CX32 (8 GB RAM minimum; PostHog’s docs recommend 16 GB for production). Self-hosted PostHog runs ClickHouse + Postgres + Kafka + Zookeeper + Redis + Object Storage + Caddy — the heaviest stack in this list.
- Pick when: SaaS product analytics where consent gate is acceptable AND you need feature flags + A/B + product analytics in one tool; your audience is logged-in users where memory mode’s no-cross-day-ID limitation is acceptable for marketing-page tracking only
- What you give up in memory mode: session replay, retention curves, cross-session funnels — basically every feature that distinguishes PostHog from Plausible. If you turn all those off, ask whether PostHog is the right tool.
Full Docker deploy: PostHog on Hetzner with Docker.
Recipe 5: GoatCounter
The minimalist choice: a single Go binary, SQLite by default, Postgres optional, and a visitor-ID mechanism that’s stronger than the others — not just hashed, but not stored at all.
Visitor identification mechanism
Per GoatCounter’s session docs: when a hit comes in, GoatCounter computes siteID + User-Agent + IP and looks up an in-memory {siteID,UA,IP} → UUIDv4 mapping. Only the UUIDv4 is persisted to disk. The mapping table is held in RAM and discarded after 8 hours. There is no salt-and-hash — the IP/UA never reach disk in any form, hashed or otherwise. Three times more aggressive than Plausible’s 24h salt rotation.
Install (single binary, ~20 min)
# 1. Download release binary (Go, ~10 MB)
wget https://github.com/arp242/goatcounter/releases/download/v2.7.0/goatcounter-v2.7.0-linux-amd64.gz
gunzip goatcounter-v2.7.0-linux-amd64.gz
mv goatcounter-v2.7.0-linux-amd64 /usr/local/bin/goatcounter
chmod +x /usr/local/bin/goatcounter
# 2. Create site (SQLite by default)
goatcounter db create site -vhost stats.example.com -user.email [email protected]
# 3. Run behind nginx (no TLS — nginx terminates)
goatcounter serve -listen :8080 -tls http -static stats.example.com
# 4. Embed tracker (5 lines of JS)
<script data-goatcounter="https://stats.example.com/count"
async src="//stats.example.com/count.js"></script>
The killer feature: image-pixel mode for newsletters and RSS feeds where JS doesn’t run. Embed <img src="https://stats.example.com/count?p=/newsletter-2026-05"> in your Mailchimp HTML email and it counts opens against your GoatCounter dashboard. No other tool in this list does this without significant custom work.
Cost & when to pick
- Cost: €0/mo if you co-host on an existing webserver (single binary, ~30 MB RAM); €4.51/mo Hetzner CX22 if dedicated
- Pick when: static blog / personal site / newsletter open-rate tracking / single-binary preference; want the strongest cookieless posture
- What you give up: custom event props (limited compared to Plausible), funnels, anything beyond “pageviews + referrers + countries”; pixel mode under-counts unique visitors (no UA fingerprint from
<img>)
Side-by-side: which recipe fits which use case
| Tool | Cookies | localStorage | Visitor-ID method | Custom events | Ecommerce | Stack complexity | Best for |
|---|---|---|---|---|---|---|---|
| Plausible CE | No | No | Daily SipHash (UA+IP+domain) at 00:00 UTC | Yes, native | Yes, native | Low (3 containers) | EU marketing teams, default safe choice |
| Matomo | No (with disableCookies) | No | Config ID heuristic, 30-min visit window | Yes | Yes (with caveats) | Medium (PHP+MariaDB) | GA-parity reports + heatmaps + session replay |
| Umami v2 | No | No | SHA-512 (site+IP+UA+salt) → UUIDv5; salt rotates monthly by default (configurable to daily) | Yes (declarative) | No | Low (Next.js+Postgres) | Marketing site, free-tier hosting OK |
| PostHog (memory) | No | No | Per-page random distinct_id (no continuity) | Yes (full SDK) | Limited | High (CH+PG+Kafka+Redis) | SaaS product, willing to lose cross-session |
| GoatCounter | No | No | In-memory UUIDv4 mapping, 8h rotation | Limited | No | Very low (single binary) | Static blog, pixel mode for newsletters |
Still unsure? The 60-second Stack Picker walks 6 questions and recommends one. For full feature comparisons across 10 tools (including non-cookieless options), see the self-hosted analytics hero pillar.
6 production pitfalls (and how to detect them)
FAQ
Is cookieless tracking legal without a consent banner?
Will I lose returning-visitor data?
Does Plausible need a cookie banner?
Can I use cookieless tracking with Google Analytics 4?
Can I run two analytics tools side-by-side?
Will Safari or Firefox break my cookieless setup?
What’s the cheapest cookieless option in 2026?
Does cookieless tracking work with React/Next.js client-side routing?
script.js does NOT auto-track pushState — load script.hash.js for hash-router SPAs or call plausible('pageview') manually in your route handler. Matomo: call _paq.push(['trackPageView']) in your router’s afterEach hook. PostHog: posthog.capture('$pageview'). Umami: umami.track(). GoatCounter: re-trigger the script’s count() function.Can I migrate historical data from GA4 into a cookieless tool?
console core:import doesn’t accept GA4 directly. The standard playbook is dual-stack for 30 days, then cut over to the cookieless tool as source of truth.Will my Google Search Console data still work without GA4?
Found this useful?
Try the Stack Picker to get a personal recommendation, or browse the install recipe library.