Skip to content
$_ setuptracking
Cookieless

Cookieless Tracking 2026: 5 Self-Hosted Setups (No Consent Banner)

17 min read
3D illustration of broken cookie banner representing cookieless tracking without consent prompts

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.

// GA4 + CONSENT BANNER
~9% data visible
  • −28% ad-blocker drop
  • −15% Safari ITP cookie cap
  • −45% banner reject
  • −3% Schrems II edge
  • + active DPA enforcement risk
// SELF-HOSTED COOKIELESS
~99% data visible
  • 0% banner reject (exempt)
  • ~0% ad-blocker (first-party)
  • EU-residency by default
  • €4.51–12/mo Hetzner CX22
  • 0 fine exposure under CNIL exemption
The GA4 + banner stack visualizes about 9% of real traffic. Self-hosted cookieless gets you the other 90%.

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 _ga cookie 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.
Browser IP + User-Agent Tracker server hash(salt + domain + IP + UA) salt rotates every 8–24h Database row opaque_hash, ts, page no IP, no UA, no PII Dashboard unique = distinct hash per rotation window salt rotates → yesterday’s hashes are now unlinkable
No cookie, no localStorage, no fingerprint. Just a server-side hash that becomes meaningless once the salt rotates.

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.
Read:  Matomo on Hetzner: Self-Host with MariaDB & Caddy (€8.21/mo, 30 min)

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

ModeCookieslocalStorageCross-day identitySession replayEU consent-banner-free?
localStorage+cookie (default)YesYesYes (months)YesNo (consent required)
localStorageNoYesYesYesBorderline (DSK 2021 says no)
memoryNoNoNo (page reload = new ID)NoYes

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

ToolCookieslocalStorageVisitor-ID methodCustom eventsEcommerceStack complexityBest for
Plausible CENoNoDaily SipHash (UA+IP+domain) at 00:00 UTCYes, nativeYes, nativeLow (3 containers)EU marketing teams, default safe choice
MatomoNo (with disableCookies)NoConfig ID heuristic, 30-min visit windowYesYes (with caveats)Medium (PHP+MariaDB)GA-parity reports + heatmaps + session replay
Umami v2NoNoSHA-512 (site+IP+UA+salt) → UUIDv5; salt rotates monthly by default (configurable to daily)Yes (declarative)NoLow (Next.js+Postgres)Marketing site, free-tier hosting OK
PostHog (memory)NoNoPer-page random distinct_id (no continuity)Yes (full SDK)LimitedHigh (CH+PG+Kafka+Redis)SaaS product, willing to lose cross-session
GoatCounterNoNoIn-memory UUIDv4 mapping, 8h rotationLimitedNoVery 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)

Pitfall DevTools signal Dashboard signal Fix
1. CDN strips X-Forwarded-For No XFF on /api/event All visitors collapse to 1 IP Use $proxy_add_x_forwarded_for not $remote_addr
2. PostHog ip: false ignored Console warning IPs still in events Project Settings → “Discard client IPs”
3. CMP loads tracker after consent Script blocked until accept Traffic 50%+ lower than reality Cookieless tools don’t need a CMP — remove gate
4. Server-side fingerprinting added FingerprintJS / ClientJS in bundle N/A — silently non-compliant Don’t bolt FingerprintJS onto a “cookieless” stack
5. US VPS reintroduces Schrems II DNS resolves to US Compliance audit fails EU residency only — Hetzner FSN/HEL, OVH, Scaleway
6. Google Fonts / YouTube embeds Outbound to fonts.googleapis.com N/A — separate compliance issue Self-host fonts; youtube-nocookie.com + click-to-load
Cookieless analytics is necessary but not sufficient — these 6 misconfigurations silently undo the work.

FAQ

Is cookieless tracking legal without a consent banner?
In the EU, cookieless self-hosted analytics qualify for the “anonymous audience measurement” exemption under most DPA interpretations — provided you anonymize IPs (mask 2-3 bytes), do not share data with third parties, limit retention, and publish a privacy notice. CNIL maintains a published exemption configuration guide. PostHog with localStorage persistence is the main exception (counts as cookies under DSK 2021 reading).
Will I lose returning-visitor data?
Yes — that’s the point. Cookieless tools count daily uniques, not cross-day uniques. Returning visitors become an estimate based on aggregate patterns rather than persistent identifiers. For SaaS with logged-in users you can pass an opaque server-issued user ID (NOT a hashed email — that’s still PII per EDPB pseudonymisation guidance) to restore cross-session tracking for authenticated users only.
Does Plausible need a cookie banner?
No, when self-hosted on EU infrastructure with default configuration. Plausible writes zero cookies and stores no PII. CNIL exemption guidance covers this configuration. The Plausible team has published their legal interpretation publicly.
Can I use cookieless tracking with Google Analytics 4?
Not really. GA4 Consent Mode v2 is not cookieless — it sends modeled signals when consent is denied, and the underlying request still attempts to set a cookie. EU regulators have not accepted this as equivalent to no-cookie analytics. If you must keep GA4, run it gated by a working consent banner, and add a self-hosted cookieless tool as a parallel data source for the consent-rejected half of your traffic.
Can I run two analytics tools side-by-side?
Yes — this is a common pattern. GA4 (consent-gated) for marketing-team reports plus self-hosted cookieless for full-traffic visibility. The cookieless data is your ground truth; GA4 is the consent-bias filtered view.
Will Safari or Firefox break my cookieless setup?
No. Browser tracking-prevention features target third-party cookies and third-party storage. Self-hosted cookieless tools don’t use either. ITP, ETP, and Privacy Sandbox all leave the no-cookie request-hash model untouched.
What’s the cheapest cookieless option in 2026?
GoatCounter on a €4.51/mo Hetzner CX11 if dedicated, or co-hosted on an existing webserver for €0/mo (single Go binary, ~30 MB RAM). For richer reporting, Plausible CE on €4.51/mo CX22 is the value choice. Umami on Vercel + Neon is free up to ~100k events/mo.
Does cookieless tracking work with React/Next.js client-side routing?
Yes, but the default Plausible 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?
Short answer: no. Long answer: BigQuery export → custom ETL → tool-specific import format. Plausible has an experimental import; Matomo’s 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?
Yes. GSC is independent of GA4 — it pulls from Google’s own crawl/index data. Removing GA4 doesn’t affect Search Console rankings, queries, or impressions. SEO reporting is unaffected.


Found this useful?

Try the Stack Picker to get a personal recommendation, or browse the install recipe library.