Skip to content
PeekWell
Join now

Back to How it works

A real finding, straight from a compliance report

This one came out of a real report. I swapped the names and dates for Hollowbrook’s and left the screenshots out.

CriticalTicketNew
ePrivacy · GDPRConsent

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.

Read more details on the wiki

Evidence

https://hollowbrook.app/4 observations
  1. 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
  2. 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
  3. 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
      }
    ]
  4. 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
  1. 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
  2. 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
  1. 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
  2. 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
  1. 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
In plain words

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

  1. In the base layout template's inline head script, set the gtag('consent', 'default', …) value of analytics_storage to 'denied', so a stored essential choice (or no choice) starts every page denied.
  2. Keep the existing update block that grants storage only when localStorage.hb_cookie_consent === 'accepted'.
  3. In static/js/site.js applyConsent(false), also delete the cookies already written by Google Analytics (_ga, _ga_HOLLOWBRK1, on domain .hollowbrook.app and path /).
  4. In GTM (GTM-HOLLOW1), make the GA4 tag require analytics_storage consent.
  5. Reject in a private window, then reload and open two more pages: expect no /g/collect with gcs=G101 and no _ga cookie. Re-scan.

Where the fix lives: codebase.

A prompt for the AI assistant that works on your website's code.
Fix prompt ready
## 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
  1. An automated browser visited the website from inside the EU, as a first-time visitor with nothing saved.
  2. 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.
  3. 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

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.