Tracking OnPage Check for GA4: tags, consent and dataLayer

The GA4 tracking on-page checks open a real URL in a headless browser (Chromium via Playwright) - once before consent is accepted, once after. That gives you a view APIs alone can't provide: what actually happens on the page itself in those first few seconds?

What does the app check?

The on-page section covers seven areas:

  1. Server-side tagging detection - does the site respond with custom GA4 endpoints or an FPID cookie?
  2. GTM implementation - are containers loaded, are there duplicates?
  3. CMP detection - 14 consent management platforms are recognised (Cookiebot, OneTrust, Usercentrics, Borlabs, CCM19, Sourcepoint and others).
  4. Consent Mode v2 - the default and updated state are read along too.
  5. Privacy/GDPR - does tracking fire before consent is accepted?
  6. Third-party tools - 9 trackers are recognised (Meta, TikTok, LinkedIn, Clarity and others).
  7. DataLayer - are events and e-commerce data spec-compliant?

When is a check triggered?

Check Threshold
Measurement ID detected Yes = green, No = red
page_view + session_start within 2 min >5 = green, <2 = red
Cross-domain cookie (_ga) consistent across domains = green
Consent status analytics granted = green, denied = warning
Tracker firing before consent every event = GDPR warning

The logic lives in app/pages/onpage.py, app/services/browser_check_service.py and app/services/onpage_check_evaluator.py.

Common causes

  • GTM not loaded → JavaScript error in the container, a Content Security Policy blocks the script, URL mismatch between the GA4 stream and the actual domain.
  • Wrong measurement ID → copy-paste bug, an old/test ID left over in the production code.
  • Tracking before consent → the GTM trigger fires on "Page Load" instead of "Consent granted", the CMP script loads after GTM or not at all.
  • Cross-domain cookie missing → the _ga cookie isn't set across the sub-/main-domain setup because the auto configuration was overridden.

How to proceed

  1. In the Auditor under OnPage, enter a URL - with a Cloud Run setup the feature may only become visible after it's activated (onpage.disabled.title).
  2. Wait for the run to finish (~10-30 s per URL, since there are two phases).
  3. Compare the two columns "Before consent" and "After consent" - anything that fires before consent is a potential GDPR risk.
  4. Check CMP detection: if no CMP is found even though one is running, identify the element in the DOM and report an issue in the Auditor if needed.
  5. For consent mode topics, open Understanding Consent Mode v2 alongside.