Google Analytics keeps running after cookies are rejected
What we saw
After a visitor rejects analytics in the banner (Manage settings, Analytics left off, Save my preferences), Google Analytics 4 (G-HOLLOWBRK1) still sent a page-view hit on every following page load: 12 of 12 loads across two test runs, including the reload, /pricing/, /how-it-works/, /faq/ and /about/. The _ga cookies set on arrival stay in place and keep being used, so the same analytics continues as if the visitor had said yes. The rule expects a refusal to actually stop the tracking, and EU data protection authorities have treated a reject choice that changes nothing as no valid choice at all. Hotjar, by contrast, stays off after rejection.
Evidence
https://hollowbrook.app/4 observations
- After RejectPage element3 Jun 2026, 09:14 UTC
Rejected via #cookie-banner [data-cookie-manage] → #cookie-prefs [data-cookie-save] with Analytics toggle left off; localStorage hb_cookie_consent = 'essential'
Recorded data
- clicks
2- analytics toggle checked
no- localStorage
essential
- After RejectNetwork request3 Jun 2026, 09:14 UTC
POST https://region1.google-analytics.com/g/collect?v=2&tid=G-HOLLOWBRK1&gcs=G101&en=page_view → 204 at t+1.8s after rejection (reload), hb_cookie_consent='essential'
Recorded data
- host
region1.google-analytics.com- tid
G-HOLLOWBRK1- gcs
G101- status
204- step
reload- consent state
essential
- After RejectOther3 Jun 2026, 09:24 UTC
GA4 page_view hit sent on 12 of 12 page loads after rejection across two runs and two starting pages; Hotjar requests after rejection: 0
Recorded data
- loads after reject
[ { "run": "run1", "page": "https://hollowbrook.app/", "step": "post_reject:reload", "ga_page_view": true, "hotjar": false }, { "run": "run1", "page": "https://hollowbrook.app/pricing/", "step": "post_reject:nav1", "ga_page_view": true, "hotjar": false }, { "run": "run1", "page": "https://hollowbrook.app/how-it-works/", "step": "post_reject:nav2", "ga_page_view": true, "hotjar": false }, { "run": "run1", "page": "https://hollowbrook.app/blog/", "step": "post_reject:reload", "ga_page_view": true, "hotjar": false }, { "run": "run1", "page": "https://hollowbrook.app/faq/", "step": "post_reject:nav1", "ga_page_view": true, "hotjar": false }, { "run": "run1", "page": "https://hollowbrook.app/about/", "step": "post_reject:nav2", "ga_page_view": true, "hotjar": false }, { "run": "run2", "page": "https://hollowbrook.app/", "step": "post_reject:reload", "ga_page_view": true, "hotjar": false }, { "run": "run2", "page": "https://hollowbrook.app/pricing/", "step": "post_reject:nav1", "ga_page_view": true, "hotjar": false }, { "run": "run2", "page": "https://hollowbrook.app/how-it-works/", "step": "post_reject:nav2", "ga_page_view": true, "hotjar": false }, { "run": "run2", "page": "https://hollowbrook.app/blog/", "step": "post_reject:reload", "ga_page_view": true, "hotjar": false }, { "run": "run2", "page": "https://hollowbrook.app/faq/", "step": "post_reject:nav1", "ga_page_view": true, "hotjar": false }, { "run": "run2", "page": "https://hollowbrook.app/about/", "step": "post_reject:nav2", "ga_page_view": true, "hotjar": false } ]
- After RejectPage element3 Jun 2026, 09:14 UTC
site.js applyConsent(false) pushes gtag('consent','update',{analytics_storage:'denied',…}) only on the current page; the inline head default on every later load is analytics_storage:'granted' and only an 'accepted' value updates it
Recorded data
- file
https://hollowbrook.app/static/js/site.js- functions
[ "applyConsent", "initCookieBanner" ]
- head default
analytics_storage: granted
https://hollowbrook.app/pricing/2 observations
- After RejectNetwork request3 Jun 2026, 09:14 UTC
POST https://region1.google-analytics.com/g/collect?v=2&tid=G-HOLLOWBRK1&gcs=G101&en=page_view → 204 at t+5.66s after rejection (nav1), hb_cookie_consent='essential'
Recorded data
- host
region1.google-analytics.com- tid
G-HOLLOWBRK1- gcs
G101- status
204- step
nav1- consent state
essential
- After AcceptNetwork request3 Jun 2026, 09:15 UTC
POST https://region1.google-analytics.com/g/collect?v=2&tid=G-HOLLOWBRK1&gcs=G111&en=page_view → 204 at t+5.25s after Accept All (baseline): the same GA4 property, now with ad storage also granted
Recorded data
- host
region1.google-analytics.com- tid
G-HOLLOWBRK1- gcs
G111- hotjar requests
6
https://hollowbrook.app/how-it-works/2 observations
- After RejectNetwork request3 Jun 2026, 09:14 UTC
POST https://region1.google-analytics.com/g/collect?v=2&tid=G-HOLLOWBRK1&gcs=G101&en=page_view → 204 at t+5.72s after rejection (nav2), hb_cookie_consent='essential'
Recorded data
- host
region1.google-analytics.com- tid
G-HOLLOWBRK1- gcs
G101- status
204- step
nav2- consent state
essential
- After RejectCookie3 Jun 2026, 09:14 UTC
After rejection, cookies _ga and _ga_HOLLOWBRK1 (domain .hollowbrook.app, ≈400 days) still present and in use; not deleted on rejection
Recorded data
- cookies
[ { "name": "_ga", "domain": ".hollowbrook.app", "lifetime_days": 400 }, { "name": "_ga_HOLLOWBRK1", "domain": ".hollowbrook.app", "lifetime_days": 400 } ]
https://hollowbrook.app/faq/1 observation
- After RejectNetwork request3 Jun 2026, 09:15 UTC
POST https://region1.google-analytics.com/g/collect?v=2&tid=G-HOLLOWBRK1&gcs=G101&en=page_view → 204 at t+5.7s after rejection (nav1), hb_cookie_consent='essential'
Recorded data
- host
region1.google-analytics.com- tid
G-HOLLOWBRK1- gcs
G101- status
204- step
nav1- consent state
essential
When a visitor opens the cookie settings, leaves analytics switched off and saves, Google Analytics carries on counting their visits on every page they open next, using the same ID it stored on arrival. It's like telling a hotel desk you don't want the newsletter, watching them nod, and still finding it in your post every week. Once someone says no, Google Analytics should go quiet on every later page and the ID it stored should be cleared. This usually comes from the default setting at the top of each page, which only remembers a 'yes' and forgets a 'no'.
The fix
- In the base layout template's inline head script, set the
gtag('consent', 'default', …)value ofanalytics_storageto'denied', so a storedessentialchoice (or no choice) starts every page denied. - Keep the existing update block that grants storage only when
localStorage.hb_cookie_consent === 'accepted'. - In
static/js/site.jsapplyConsent(false), also delete the cookies already written by Google Analytics (_ga,_ga_HOLLOWBRK1, on domain.hollowbrook.appand path/). - In GTM (GTM-HOLLOW1), make the GA4 tag require
analytics_storageconsent. - Reject in a private window, then reload and open two more pages: expect no
/g/collectwithgcs=G101and no_gacookie. Re-scan.
Where the fix lives: codebase.
## What was observed (EU-02)
On https://hollowbrook.app/ a visitor who clicks "Manage settings", leaves Analytics off and clicks "Save my preferences" (localStorage `hb_cookie_consent` = `essential`) still gets `POST https://region1.google-analytics.com/g/collect?...tid=G-HOLLOWBRK1&gcs=G101&en=page_view` on every later page load (reload, `/pricing/`, `/how-it-works/`, `/faq/`, `/about/`). The `_ga` and `_ga_HOLLOWBRK1` cookies set before the choice remain and keep being used.
## What it should do instead
After the visitor saves with Analytics off, every later page load starts with analytics storage denied: no `/g/collect` hit with `gcs=G101`, and the `_ga` / `_ga_HOLLOWBRK1` cookies are removed. Hotjar already behaves this way; keep it.
## Where to look
This looks like a project with server-rendered templates and one shared base layout; confirm by finding the file that includes the GTM snippet. Grep for `analytics_storage`, `GTM-HOLLOW1` and `hb_cookie_consent`. Two places matter: the inline `<head>` script in the base layout template (it calls `gtag('consent', 'default', {'analytics_storage': 'granted', ...})` and only updates when the stored value is `accepted`), and `static/js/site.js` (`applyConsent`, `initCookieBanner`), whose denied update applies only to the current page.
## The change
1. In the head script, make the default `'analytics_storage': 'denied'` (ad keys stay denied). Keep the `=== 'accepted'` update block.
2. In `applyConsent(false)` in `site.js`, after the denied update, delete `_ga` and every `_ga_*` cookie: set each with `expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.hollowbrook.app`.
3. Apply this in every layout template that includes the GTM snippet.
## If it is not in this repository
If GA4 still fires after these edits, print numbered steps for Google Tag Manager: Tags → GA4 tag for G-HOLLOWBRK1 → Advanced Settings → Consent Settings → require `analytics_storage` → Submit → Publish.
## How to verify
Start the dev server; in a fresh headless browser context, click `[data-cookie-manage]`, then `[data-cookie-save]`; reload and open two other pages, waiting 7 seconds each. Expect no `_ga*` cookies and no `/g/collect` request with `gcs=G101`. Ask for a PeekWell re-scan to confirm.
## Boundaries
Do not change unrelated behaviour. Do not remove a tool or rewrite legal text beyond what is described; where a business decision is needed (keep or drop a tracker), stop and ask. Summarise what you changed and how you tested it.How we scanned
- An automated browser visited the website from inside the EU, as a first-time visitor with nothing saved.
- On one visit it rejected analytics in the banner, on another it accepted everything, and each time it recorded what loaded on the pages that followed.
- A second run gave the same result.
Limitations
The privacy policy mentions a footer cookie-settings link, but none was found, so changing a choice later could not be tested. Sign-in and checkout pages were not loaded. The website was visited from one EU country only. Visitors from other countries could see a different banner, though nothing suggested they would.
References
- Enforcement case Spanish authority (AEPD) sanctions Valencian restaurant company Begin Restaurantes S.L. for Google Analytics _ga cookies set before consent and a Reject button that did not work, PS/00405/2023 (2023, €2,000 reduced to €1,600)
- Guidance CNIL: refusing cookies must be as simple as accepting them; formal notices to about 90 organisations (December 2021)
- Guidance EDPB report of the Cookie Banner Taskforce: common position of EU authorities on missing first-layer reject buttons and other banner practices (January 2023)
- Statute ePrivacy Directive 2002/58/EC, consolidated text, Article 5(3): storing or reading information on a visitor's device needs consent (EUR-Lex)
Responses
No responses yet.
A company's response is shown next to the finding and does not change the score. Only a PeekWell ruling or a new scan does.
EU-02 · check version 1. For information only. Not legal advice.
