Skip to content

fix(site): make the analytics actually cookieless - #69

Merged
vishr merged 1 commit into
mainfrom
fix/analytics-actually-cookieless
Aug 18, 2026
Merged

fix(site): make the analytics actually cookieless#69
vishr merged 1 commit into
mainfrom
fix/analytics-actually-cookieless

Conversation

@vishr

@vishr vishr commented Aug 18, 2026

Copy link
Copy Markdown
Member

The component claimed to set no cookies. It set two.

What was wrong

client_storage: "none" passed inside gtag("config", ...) is not a directive gtag recognises. It was forwarded as a custom event parameter — every hit carried ep.client_storage=none — and GA4 wrote _ga and _ga_<id> anyway.

That invalidated the central claim of #66: "no _ga cookie, so the site needs no consent banner." It wrote _ga, and in the EU that needs consent.

The fix

Consent Mode, declared before js and config:

gtag("consent", "default", {
  analytics_storage: "denied",
  ad_storage: "denied",
  ad_user_data: "denied",
  ad_personalization: "denied",
});

Measured in a real browser, before and after

Before After
document.cookie _ga, _ga_C1KM4SN3JR (none)
Consent signal absent gcs=G100
Storage flag ep.client_storage=none pscdl=denied
page_view recorded 204 204
Ad personalisation npa=1 npa=1

Only the cookies changed. Measurement still works.

Why it survived review

Every earlier check tested the wrong thing. Grepping the built HTML for client_storage: "none" proved the string was emitted, never that GA honoured it. Executing the script against a DOM stub cannot observe cookies — the stub has no cookie jar. Both passed; both were worthless for this claim. Only a real browser could catch it.

This is the second defect in this one file that passed verification while not doing what it said — the first shipped the whole IIFE inside a template literal, inert.

Note

google-analytics.com/g/collect fails with net::ERR_SSL_PROTOCOL_ERROR on the machine this was tested from, both before and after the change. The google.com/g/collect fallback returns 204 so hits land. That looks like local TLS interception, not a site problem.

The component claimed to set no cookies. It set two.

`client_storage: "none"` passed inside `gtag("config", ...)` is not a directive
gtag recognises. It forwarded it as a custom event parameter — every hit carried
`ep.client_storage=none` — and GA4 wrote `_ga` and `_ga_<id>` regardless. The
setting did nothing except add a meaningless field to the payload.

Consent Mode is the mechanism that works, declared before `js` and `config`:

    gtag("consent", "default", {
      analytics_storage: "denied",
      ad_storage: "denied",
      ad_user_data: "denied",
      ad_personalization: "denied",
    });

Measured in a real browser before and after, on the built output:

    before   document.cookie -> _ga_C1KM4SN3JR=GS2.1...; _ga=GA1.1...
             payload         -> ep.client_storage=none
    after    document.cookie -> (none)
             payload         -> gcs=G100  pscdl=denied

`gcs=G100` is GA acknowledging the denial. A page_view is still recorded (204),
title and location are still correct, and npa=1 still reports ad
personalisation off. The only thing that changed is that the claim is now true.

Worth recording why this survived review. Every earlier check tested the wrong
thing: grepping the built HTML for `client_storage: "none"` proved the string
was emitted, never that GA honoured it, and executing the script against a DOM
stub cannot observe cookies because the stub has no cookie jar. Both passed.
Only a real browser could see it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vishr
vishr merged commit 10f7a5d into main Aug 18, 2026
5 checks passed
vishr added a commit that referenced this pull request Aug 18, 2026
fix(site): make the analytics actually cookieless
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant