If you've set up Google Consent Mode v2 and it still looks like GA4 or Google Ads is firing before a visitor makes a choice, you're not alone — it's one of the easiest integrations to get technically present but functionally broken. The banner shows up, the consent categories look right, and tags still fire anyway. In practice, "not working" almost always comes down to one of four things. Here's what's actually happening in each case, and how to check which one you've got. (See Google's own Consent Mode documentation for the full technical reference this is based on.)
First, confirm it's actually broken
Before anything else: clear your cookies (or use a fresh incognito window) and reload the page. If you've already granted consent once, your browser is caching that choice — the site will look "broken" simply because it correctly remembers you already said yes. This single step accounts for a surprising number of false alarms.
With a clean session, open DevTools → Network tab, filter for collect or gtm.js, and
reload the page without clicking anything on the banner. If you see requests to
google-analytics.com/g/collect or similar before you've made a choice, it's really
broken — keep reading.
1. The default consent state isn't actually "denied"
Consent Mode v2 works by setting a default state before any tag fires, then updating that state once the visitor chooses. The most common failure is a Google Tag Manager container-ordering issue: the default command never actually runs before Google Analytics or Google Ads loads, because the consent default tag fires on a trigger that isn't guaranteed to run first.
How to check: in the DevTools console, before interacting with the banner, run
dataLayer and look for a consent entry with "default" — check whether
ad_storage, analytics_storage, ad_user_data, and ad_personalization are all set to
"denied". If any of them are missing, or the entry isn't there at all before your
analytics tags load, that's your problem.
The fix: Google Tag Manager has a dedicated trigger type built exactly for this — Consent Initialization – All Pages. Setting the default-consent tag to fire on that trigger, rather than a regular Page View or DOM Ready trigger, guarantees it runs before any other tag in the container, closing the ordering gap directly.
2. The consent update never fires when someone clicks Accept or Reject
The default can be set correctly, and the banner can look and behave perfectly — but if
clicking "Accept" doesn't actually call gtag('consent', 'update', {...}), nothing
changes. This happens most often with a self-built or heavily customized banner, where the
button's click handler was wired to update the on-screen UI but never connected to the
actual consent API.
How to check: click through the banner, then check dataLayer again for a
gtm.consent or a second consent entry with "update". If your first default entry
is the only consent-related entry in dataLayer even after clicking Accept, the update
call isn't firing.
The fix: connect the button's click handler directly to gtag('consent', 'update', {...}) with the categories the visitor actually chose — a UI state change alone, without
that explicit call, never reaches Google's tags at all.
3. Basic vs. Advanced consent mode mismatch
Google Consent Mode v2 has two implementation modes. Basic mode blocks Google tags from loading at all until consent is granted. Advanced mode lets tags load immediately but sends cookieless "pings" instead of full data until consent is granted. Teams often intend one and accidentally implement the other. The most common version: someone expects Basic-mode blocking behavior, but the actual GTM configuration is set up for Advanced mode — which correctly sends some network traffic pre-consent by design, and gets mistaken for a broken integration.
How to check: those pre-consent network requests you saw in DevTools — do they have a
gcs parameter in the URL (a short encoded consent-state string)? If yes, that's Advanced
mode's cookieless ping behavior working as designed, not a leak. If there's no gcs
parameter and full request payloads are going out anyway, tags aren't respecting consent
mode at all.
If you actually wanted Basic mode: the fix is reconfiguring each tag's firing trigger to wait on the consent signal itself, rather than firing immediately on Page View — Advanced mode's pings are a deliberate design choice, not something you disable with a single setting.
4. The CMP isn't actually wired to Consent Mode
The most common root cause of all: the CMP — Consent Management Platform, the cookie
banner tool itself (Cookiebot, OneTrust, Termly, or a custom one) — looks and functions
correctly as a banner, but was never actually connected to Google's gtag('consent', ...)
API in the first place. This happens frequently after a banner migration, a GTM container
rebuild, or when a CMP's auto-blocking feature was disabled without anyone reconnecting the
manual consent signal.
How to check: this is the same dataLayer check from #1 and #2 — if there's no
consent entry at all, regardless of what the banner UI shows, the CMP was never
connected to Consent Mode in the first place.
The fix: reconnect the CMP's native Consent Mode integration rather than relying on its blocking feature alone — Cookiebot, OneTrust, and Termly all ship a documented, built-in Consent Mode v2 integration; the fix is almost always re-enabling it, not building a custom bridge from scratch.
If you don't want to check this by hand
This is exactly what a pre-consent scan is built to catch automatically — which tags
fired, whether a consent default was present before they did, and whether Basic or
Advanced mode behavior actually matches what's configured. Worth running once you've fixed
whichever of the four this turned out to be, just to confirm the fix actually took.
If you'd rather do the DevTools check yourself first, the underlying method — independent of Consent Mode specifically — is the same one covered in how to check if cookies fire before consent. And if what brought you here is a shrinking Google Ads or GA4 remarketing audience, see is consent gating shrinking your remarketing audience — items #2 and #3 there point straight back to the two failure modes above.
If Consent Mode is technically firing but ad_user_data or ad_personalization
specifically is missing or stuck denied — a different, narrower failure than the four
above — see Consent Mode v2 missing ad_user_data and
ad_personalization for that specific fix.
Petrus, Founder — ConsentCheck. Built by a developer who implements this stack for a living — this is the exact troubleshooting order I actually work through.