Google Consent Mode v2 setup for agencies (the version that actually works)
Most Consent Mode v2 implementations are wrong in subtle ways that block 60-80% of EU conversions silently. This is the actual setup we ship for agency clients — what each consent signal does, how to wire it through GTM, and how to verify it didn't break overnight.
TL;DR
Consent Mode v2 has six consent signals (ad_storage, analytics_storage, ad_user_data, ad_personalization, functionality_storage, security_storage). Most implementations set defaults but never wire the cookie banner's "update consent" callback through to GTM, so every EU user shows as denied forever. The setup that works: (1) default consent set to denied for ad/analytics in EU regions only, (2) update consent triggered by the cookie banner's accept/decline callback, (3) advanced consent mode enabled (sends modeled conversions when consent is denied so you don't lose all signal), (4) per-tag consent requirements verified in GTM Preview. Verification takes 15 minutes per client. Skip any step and you'll quietly under-report 60-80% of EU conversions.
The problem with Consent Mode v2 isn't that it's hard. It's that it has six independent consent signals, two consent states (default vs. update), regional behavior, and a fork between "basic" and "advanced" mode — and most cookie-banner integrations get one of those wrong in a way that doesn't surface until the EU client's quarterly review shows ad spend that produced no measurable conversions.
This is the version we ship for agency clients. Not the official Google walkthrough; the one that survives the audits.
What Consent Mode v2 actually does
Consent Mode is Google's mechanism for letting Google tags (gtag.js, GA4, Google Ads) respect user consent without blocking the tags entirely. When consent is granted, tags fire normally with cookies. When consent is denied, tags fire in a degraded mode that:
- Does NOT set or read cookies
- Does NOT send personally-identifiable data
- DOES send "consent-less pings" with anonymized session info that Google uses to model unobservable conversions
The "advanced consent mode" path (the one you want) uses these consent-less pings to attribute conversions that would otherwise be invisible. The "basic consent mode" path just blocks the tags entirely. The difference: basic loses 60-80% of EU conversion signal; advanced recovers most of it through modeling.
V2 (rolled out March 2024) added two new signals (ad_user_data, ad_personalization) that explicitly differentiate "is the data sent to Google" from "can Google use it for personalization." Before V2 these were conflated; the new granularity matters for EU regulatory compliance and unlocks the modeled conversions.
The 6 consent signals (and what each blocks)
Get these wrong and you'll either over-block (lose conversions) or under-block (regulator visit).
| Signal | Controls | Default in EU |
|---|---|---|
ad_storage | Cookies for ads (DoubleClick, conversion linker) | denied |
analytics_storage | Cookies for analytics (GA4, conversion measurement) | denied |
ad_user_data | Whether Google receives user identifiers for ads | denied |
ad_personalization | Whether Google can use data for personalized ads | denied |
functionality_storage | Site functionality (preferences, language) | granted (usually) |
security_storage | Security features (fraud detection) | granted (always) |
The four denied defaults are what differentiate EU compliance from US. In US (and most non-EU regions), all six default to granted and the cookie banner is informational rather than gatekeeping.
The setup that works
Five steps. Each one is independently a place to break things.
Step 1: Pick a cookie banner that supports Consent Mode v2
Not every cookie banner does. As of mid-2026, working integrations: OneTrust, Cookiebot, Iubenda, Usercentrics, CookieYes, Termly. NOT working / partial: most homegrown banner libraries, some older WordPress plugins.
The banner needs to:
- Set the
default consentstate on page load (before any other Google tags fire) - Update the consent state when the user accepts/declines
- Persist the user's choice (cookie + localStorage)
- Re-apply on subsequent page loads
If the banner only does (1), every user looks denied forever. If it skips (2), accepting consent doesn't actually grant anything. Both are common.
Step 2: Wire default consent BEFORE any Google tags fire
In your <head>, before the GTM container snippet:
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Default to denied for EU; granted elsewhere. Region detection
// runs on the server (or via a CDN edge function) — never trust
// client-side region detection for compliance purposes.
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'functionality_storage': 'granted',
'security_storage': 'granted',
'wait_for_update': 500 // ms to wait for the banner to call gtag('consent', 'update', ...)
});
</script>
<!-- Now the GTM container snippet -->
The wait_for_update: 500 tells gtag to hold tag firing for 500ms while the cookie banner has a chance to call gtag('consent', 'update', ...). Without this, tags fire under the default denied state even if the user has consented in a previous session.
Step 3: The cookie banner must call gtag('consent', 'update', ...)
Most cookie-banner platforms have a built-in Google Consent Mode integration that handles this. Verify the integration is enabled:
- OneTrust: Cookie Categories → Google Consent Mode → enable per category
- Cookiebot: Settings → Google Consent Mode → enable, set per category
- Iubenda: Configuration → Tag Management → enable Google Consent Mode
If your banner doesn't have a built-in integration, you write the JS yourself in the banner's accept/decline callback:
// In the banner's `onAccept` callback:
gtag('consent', 'update', {
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted'
});
// In the banner's `onDecline` callback:
// (Don't need to call update — defaults are already 'denied'.)
Step 4: Enable advanced consent mode (the modeled-conversions path)
Google's advanced consent mode sends consent-less pings that allow modeling of denied-state conversions. Enable in:
- Google Ads: Admin → Linked Accounts → Cookies → enable Advanced Consent Mode
- GA4: Admin → Data collection and modification → Data settings → Data collection → enable "Collect ads-personalization data even from regions requiring consent" (the toggle name varies by GA4 version)
Without advanced consent mode, denied users contribute zero data. With it, denied users contribute consent-less pings that get modeled into your reports — typically recovering 50-70% of the would-be-lost conversions.
Step 5: Per-tag consent requirements in GTM
Each tag in GTM has a consent requirement. Verify it matches the consent signal it actually depends on:
- GA4 Configuration tag → requires
analytics_storage - Google Ads Conversion tag → requires
ad_storage - Google Ads Remarketing tag → requires
ad_storage+ad_user_data+ad_personalization - Custom HTML tags → may not auto-detect; set manually
In GTM: Tag Configuration → Consent Settings → "Require additional consent for tag to fire" → check the right boxes.
The most common mistake here: leaving Custom HTML tags with no consent requirement, so they fire even when consent is denied. Regulator-visible.
How to verify it actually works
Three checks, 15 minutes total per client:
Check 1: GTM Preview mode
Open Preview on the live container. Refresh the page in Preview tab. Look at the "Consent" tab:
- Default state should match what your
<head>script sets (deniedfor ad/analytics in EU) - After accepting consent in the banner, "Update" event should appear with all four ad/analytics signals →
granted - Tags listed under "Tags Fired" should match expected consent-respecting behavior
If "Update" event doesn't appear when you accept consent: your banner isn't calling gtag('consent', 'update', ...). Step 3 is broken.
Check 2: Tag Assistant Companion (Chrome extension)
Install Tag Assistant. Visit the live site. Tag Assistant shows the consent state in real time + which tags fired with which consent. Easier than GTM Preview for non-developers on the agency team.
Check 3: Google Ads / GA4 dashboard delta
Compare the "EU traffic" segment in GA4 before and after your Consent Mode rollout. A working setup shows:
- Total events drop by ~30-40% in EU (from blocked tags)
- Modeled conversions appear in GA4 reports (look for "(modeled)" annotation)
- Ad Manager Conversion volume in EU recovers most of its pre-rollout baseline within 2-3 weeks
If you see a 60-80% drop in EU events with NO modeled-conversion recovery: advanced consent mode isn't enabled (Step 4) or banner integration isn't wired (Step 3).
The agency-side discipline
Consent Mode is a per-client setup, but the discipline is per-agency. Three things to standardize:
- A house standard cookie banner. Pick one (OneTrust, Cookiebot, Iubenda, etc.) and use it on every EU-touching client. Per-client banner choice fragments your engineer's debugging skill.
- A house template for the
<head>consent block. The 5-step setup above as a snippet you paste into every client. Variations are bug surfaces. - A monthly EU-traffic delta check. Add it to the 21-item checklist. If EU conversions dropped >70% month-over-month, something's wrong.
What's NOT in this post
We're deliberately not covering:
- The legal/regulatory side of consent (CMP requirements, IAB TCF, country-specific rules) — that's a lawyer question
- Server-side consent enforcement (advanced topic; most agencies don't need it for V1 setup)
- Consent-aware audience segmentation (V2 of consent maturity; most agencies should get the basics right first)
The setup above is the minimum that works. Get this right, then layer on the advanced topics as the client engagement matures.
The takeaway
Consent Mode v2 is five steps that most agencies do four of. The fifth step — wiring gtag('consent', 'update', ...) from the banner — is the one that breaks most often, and it's silent when broken. Verify with GTM Preview after every banner change, every banner version upgrade, and every quarterly review. Skip the verification and you'll quietly lose 60-80% of EU conversion data without anyone noticing until the renewal conversation.
Try Phloz free if you want consent-mode state tracked as a typed node per client with a "last verified" timestamp baked in.