Set default consent to “denied” before any Google tag fires, then push an “update” command the instant a user makes a choice. That single sequence, applied correctly, is what separates a compliant Consent Mode V2 setup from one that leaks data or breaks Google Ads reporting.
Here’s the minimum viable checklist:
- Send all four V2 signals:
ad_storage,analytics_storage,ad_user_data,ad_personalization - Fire defaults through GTM’s Consent Initialization trigger, which runs before every other tag
- Pick basic mode (block tags entirely) or advanced mode (load tags with denied defaults and send cookieless pings) based on your architecture
- Push the update command the moment your consent banner registers a choice, not on page reload
Skip any one of these and you either lose data you’re entitled to collect or transmit data you’re not. Both outcomes cause problems: one wrecks your reporting, the other risks a compliance complaint. The rest of this guide walks through the exact code, GTM tag setup, and testing steps to get it right the first time.
Key Takeaways
Consent Mode V2 setup succeeds when default consent is denied before any tag fires, updates push immediately on user choice, and all four signals travel through every layer of the stack.
| Point | Details |
|---|---|
| Send all four signals | Include ad_storage, analytics_storage, ad_user_data, and ad_personalization in every default and update call. |
| Fix the ordering first | Use GTM’s Consent Initialization trigger so defaults always fire before any other tag. |
| Choose your mode deliberately | Basic mode blocks tags outright; advanced mode enables cookieless pings and richer conversion modeling. |
| Map your CMP carefully | Translate banner categories or TCF v2 purposes to the four signals individually, don’t assume a clean match. |
| Test before and after publish | Verify default timing, update speed, and cookie behavior using Tag Assistant and GTM preview. |
Table of Contents
- What Is Consent Mode V2 and Why Does It Matter for Tagging?
- Basic vs Advanced Consent Mode: How Do You Choose?
- What Do You Need Before You Start Configuring Consent Mode?
- How Do You Set the Default Consent State?
- How Do You Update Consent State After a User Chooses?
- How Do You Connect a CMP or TCF v2 Signals to Consent Mode?
- Which GTM Features Enforce Correct Consent Ordering?
- What Changes When You Add Server-Side Tagging?
- How Do You Test and Verify Consent Mode Is Working?
- What Does a Complete Consent Mode V2 Flow Look Like?
- What Exactly Changed From Consent Mode V1 to V2?
- When and Where Does Consent Mode V2 Actually Matter?
- What Do Hands-On Implementations Teach You About Consent Mode?
- Frequently Asked Questions
- Sources
What Is Consent Mode V2 and Why Does It Matter for Tagging?
Consent Mode works as a signal layer between your consent choices and Google’s tags. Instead of physically blocking or unblocking scripts, it tells gtag.js, Google Tag Manager, and connected Google products how to behave based on what the user permitted. A tag doesn’t ask “is this allowed?” anymore. It asks “what did the user say?” and adjusts.
Version 2 added two new signals that weren’t in the original release: ad_user_data and ad_personalization. Combined with the original ad_storage and analytics_storage, that’s four signals total, and all four are required for advertisers using Google Ads features in the EEA, Switzerland, and the UK.
Why bother upgrading at all? A few concrete reasons:
- It enables cookieless pings, meaning Google can still model conversions even when a user denies storage consent
- It preserves conversion modeling accuracy instead of leaving gaps in your reporting
- It’s a prerequisite for certain Google Ads features, particularly in regions with strict privacy enforcement
The data flow looks like this: your consent banner (the CMP) captures the choice, pushes it to the dataLayer, Google Tag Manager or gtag.js reads it, and an optional server-side container downstream respects the same signals.
Basic vs Advanced Consent Mode: How Do You Choose?
The two modes handle the moment before consent completely differently. Basic mode blocks Google tags from loading at all until the user responds. Advanced mode loads the tags immediately, but with consent defaulted to denied, and sends cookieless pings while it waits for an update.
That difference cascades into everything else: how much data you can model, how complex your setup gets, and whether server-side tagging is even feasible.
| Dimension | Basic mode | Advanced mode |
|---|---|---|
| Tag loading before consent | Tags do not fire at all | Tags fire immediately with denied defaults |
| Data sent pre-consent | None | Cookieless pings only |
| Conversion modeling | General model, less granular | Advertiser-specific modeling |
| Implementation complexity | Lower | Higher, especially with server-side setups |
Pick basic mode if your stack is simple, you have no server-side container, or your legal team wants zero calls to Google before an explicit yes. Pick advanced mode if you need cross-page conversion modeling, you’re running server-side tagging, or you rely on advertiser-specific modeling to fill gaps in denied-consent traffic.
A quick gut check: if your Google Ads account depends heavily on smart bidding, advanced mode’s richer modeling usually pays for the added complexity. If you’re running a lean analytics setup with no ad spend riding on the data, basic mode is simpler to build and easier to audit.
What Do You Need Before You Start Configuring Consent Mode?
Before touching a single line of gtag.js or opening GTM, confirm you have the pieces in place. Missing one of these turns a half-day setup into a week of debugging.
Required components:
- A CMP or custom banner capable of emitting a
dataLayerevent (Consent Mode does not include a banner itself; it just reacts to one) gtag.jsor Google Tag Manager installed on every page, not just the homepage- Edit access to the GTM container, plus Google Ads and Google Analytics account access if you’re verifying downstream reporting
Decisions to lock down first:
- Basic or advanced mode, based on the comparison above
- Client-side only, or client-side plus server-side tagging
- Persistence method for consent choices: first-party cookie or
localStorage - A
wait_for_updatevalue for asynchronous banners (more on this below)
Regional considerations matter here too. If any portion of your traffic comes from the EEA, UK, or Switzerland, your default handling needs to assume denial until proven otherwise, and your Google Ads account may simply stop showing certain features without the full V2 signal set active.
How Do You Set the Default Consent State?
This is the step that trips up most implementations, and it’s non-negotiable: the default consent state must fire before any measurement or config command runs. If your analytics tag loads first and your consent default fires second, you’ve already sent data you shouldn’t have. That ordering mistake is the single most common failure mode in Consent Mode deployments.
For gtag.js sites, the order in your <head> matters:
- Load the
gtag.jssnippet - Immediately call
gtag('consent', 'default', {...})with all four signals set to'denied' - Only then call
gtag('config', ...)or any measurement commands
A minimal default call looks like this in pseudocode:
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'wait_for_update': 500
});
For Google Tag Manager, build a dedicated Default Consent tag that fires on the Consent Initialization trigger. This trigger type exists specifically to run ahead of everything else in the container, whether you configure it via setDefaultConsentState in a template or a Custom HTML tag calling the same command.
Two more parameters worth setting at default time: ads_data_redaction (strips click IDs like gclid when ad_storage is denied) and url_passthrough (lets click IDs travel through the URL instead of a cookie when needed). Set security_storage sensibly too, since it governs authentication and fraud-prevention cookies separate from advertising.
Pro Tip: Start wait_for_update at 500 milliseconds, which Google’s own documentation cites as a safe default. If your CMP loads slowly on mobile connections, test bumping it to 1000ms rather than guessing, then measure the actual delay your banner introduces before committing to a number.
How Do You Update Consent State After a User Chooses?
The default state buys you compliance for the first few milliseconds. The update command is what actually changes behavior once a real person makes a choice, and it needs to fire the moment that happens, not on the next page load.
Your CMP should push a dataLayer event containing granted or denied values for each category the user interacted with. That event is the trigger for everything downstream.
In gtag.js, the update call mirrors the default structure:
gtag('consent', 'update', {
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted'
});
Persist that choice in a first-party cookie or localStorage so returning visitors don’t see the banner again and so your default call on the next visit can reflect their prior decision.
In GTM, this means a Custom Event trigger tied to whatever event name your CMP pushes, feeding into data layer variables that map cleanly to each of the four signals, which then fire an Update Consent tag calling updateConsentState.
Watch for these edge cases:
- If the CMP fires its consent event before
gtm.jsfinishes loading, that first push can get missed. Re-push the same event once GTM confirms it has loaded. - Adjust
wait_for_updateif your CMP consistently takes longer than the default window to respond. - Test that the update shows up immediately in the Tag Assistant events stream. If there’s a visible lag between the click and the signal change, something in your event wiring is off.
How Do You Connect a CMP or TCF v2 Signals to Consent Mode?
Most consent management platforms don’t speak “ad_storage” and “analytics_storage” natively. They speak in banner categories like “Marketing” and “Analytics,” or in TCF v2 purpose numbers. Someone has to map one to the other, and getting that mapping wrong is the most common integration mistake.
A straightforward mapping typically looks like: Marketing/Advertising cookies map to ad_storage, ad_user_data, and ad_personalization; Analytics cookies map to analytics_storage. But your CMP’s category names won’t always line up neatly with the four signals, so check each one individually rather than assuming a one-to-one match.
For CMP selection and setup, GTM’s Template Gallery offers pre-built consent templates from major providers that handle both the default and update pushes automatically, which saves you from writing custom mapping logic. If your CMP isn’t in the gallery, you’re building a custom template or wiring a Custom HTML tag by hand.
Complianz, a widely used CMP plugin for WordPress, exposes toggles specifically for Consent Mode integration, which simplifies mapping banner categories to the four signals without touching code.
TCF v2 adds another layer: its purposes (like “Purpose 1: Store and/or access information on a device”) need translating into Consent Mode signals, and that translation isn’t always automatic depending on your CMP vendor. A TCF purpose reference helps when you’re mapping manually. The most common gotcha with asynchronous banners: if the CMP hasn’t finished initializing when your default consent call fires, you can end up with a brief window of undefined behavior, which is exactly what wait_for_update exists to prevent.

Which GTM Features Enforce Correct Consent Ordering?
Three GTM features do most of the heavy lifting once your basic setup is in place, and skipping any of them leaves gaps that are hard to spot until something breaks in production.
The Consent Initialization trigger solves the race-condition problem outright: it’s engineered to fire before every other tag in the container, which means your default consent tag never has to compete with an analytics tag for who loads first.
At the tag level, Additional Consent Checks (found under Advanced Settings on any tag) let you require specific consent types before that tag is allowed to fire. You can require ad_storage, analytics_storage, or a custom consent type your CMP defines, and GTM will simply refuse to fire the tag until that condition is met.
The Consent Overview page, once enabled, groups every tag in your container by consent status, making it trivial to spot which ones show “Consent Not Configured” versus properly configured tags. This is the fastest way to catch a tag you forgot to gate.
Pro Tip: Open Consent Overview in preview mode before every publish. If any Google tag doesn’t show a green consent check, it means that tag isn’t respecting the signals you think it is, and you’ll want to fix it before it ships.
What Changes When You Add Server-Side Tagging?
Server-side tagging shifts where consent enforcement happens, but the signals themselves don’t change. You still need a web container collecting consent from the visitor’s browser. What’s different is that a server container, running GA4’s client and Conversion Linker, has to receive and respect those same four signals before it processes anything.
Consent parameters get appended to the requests your web container sends to the server container, encoded in what Google calls the gcs (Google Consent Status) parameter. Server-side tags then read that encoding and behave accordingly, denying storage or redacting identifiers exactly as a client-side tag would.
Two settings matter more in server-side setups than client-side ones: enable url_passthrough on the client tag so click identifiers like gclid travel via URL parameters instead of cookies when storage is denied, and confirm ads_data_redaction actually strips those identifiers server-side when required.
Regional handling doesn’t change conceptually for EEA, UK, or Switzerland traffic, but server-side setups make it easier to centralize that logic in one place instead of scattering conditional code across every page template.
To test it, inspect the raw HTTP requests hitting your server container and confirm the gcs/gcd encoding actually reflects the consent state you expect, not just what you assume it should be.
How Do You Test and Verify Consent Mode Is Working?
Run this checklist before and after every publish. Skipping the post-publish check is how broken consent setups end up live for weeks before anyone notices.
- Confirm the default consent call fires before
gtm.jsloads, using GTM’s preview mode event stream - Deny consent, then confirm no advertising or analytics cookies get written in your browser’s storage inspector
- Accept consent, then confirm the update fires immediately and cookies get written within the same page interaction
- Simulate a slow-loading CMP and confirm
wait_for_updateactually holds the line until the update arrives - Navigate through a multi-page flow after denying, confirming the denied state persists across pages
For debugging, three tools do most of the work: Tag Assistant’s preview mode for a visual event stream, GTM’s own preview environment for tag firing order, and your browser’s network tab for inspecting whether requests are cookieless pings or full cookie writes.
Look specifically for gclid redaction in outgoing requests when ads_data_redaction is active, and confirm gclid only appears via URL passthrough when that’s the intended behavior, not as a stray cookie value.
The most common failure pattern: a tag fires before the Consent Initialization trigger completes, usually because someone added a tag with a custom trigger instead of relying on GTM’s built-in ordering. The fix is almost always to re-check that every consent-sensitive tag actually depends on the initialization sequence rather than firing independently.
What Does a Complete Consent Mode V2 Flow Look Like?
Putting the pieces together, here’s the order of operations from page load to a fully respected consent choice:
- The Google tag (
gtag.jsor GTM container snippet) loads - The default consent push fires immediately, all four signals denied, with
wait_for_updateset - The CMP loads, either directly or via GTM’s Consent Initialization trigger
- The user interacts with the banner; the CMP emits a
dataLayerevent with their choice - GTM’s Consent Update tag (or the equivalent
gtag.jsupdate call) fires, reading the CMP’s values - Guarded Ads and GA4 tags, previously blocked or limited by Additional Consent Checks, respond to the new signal state
A default push, in pseudocode, sits in your dataLayer array before anything else:
dataLayer.push({
'event': 'default_consent',
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied'
});
The update push, triggered by the CMP’s own event, follows the same shape with granted or denied values reflecting the actual choice:
dataLayer.push({
'event': 'consent_update',
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'denied'
});
Persist the final choice in a first-party cookie or localStorage so the next page load’s default call can reflect the returning visitor’s prior decision instead of starting from scratch. In GTM, wire data layer variables to read each of the four values from the CMP’s event object, then pass those variables directly into the Update Consent tag’s fields.
Before calling it done, run the full sequence in a staging environment: deny, verify no cookies write, accept, verify cookies write, and check the Tag Assistant stream shows both the default and update firing in the correct order.
What Exactly Changed From Consent Mode V1 to V2?
If you’re running V1, the upgrade path is narrower than it looks. You’re not rebuilding your consent architecture, just adding fields and confirming a few settings.
New fields to add: ad_user_data and ad_personalization, sitting alongside your existing ad_storage and analytics_storage calls in both the default and update commands.
Migration checklist:
- Update every default and update push in your codebase or GTM tags to include the two new fields
- Verify
ads_data_redactionandurl_passthroughare configured correctly for your architecture - Update any GTM CMP templates to the versions supporting V2, since older template versions may not send the new signals
- Recheck Consent Overview to confirm no tags are silently missing the new parameters
A V2-compliant default call, with all four fields present, looks like this:
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied'
});
V2 became necessary the moment Google Ads features tied to advertiser-specific modeling started requiring it in the EEA, Switzerland, and the UK. If your Google Ads account serves any of that traffic, this isn’t an optional upgrade. Anyone running Google Ads campaigns for regulated industries will notice missing modeling data faster than most, since those accounts tend to lean harder on conversion accuracy.
When and Where Does Consent Mode V2 Actually Matter?
Enforcement isn’t uniform globally, and that matters for prioritizing your rollout. Consent Mode V2 is effectively mandatory for advertisers using Google Ads features while serving traffic from the EEA, Switzerland, or the UK. Outside those regions, Google recommends it, but it’s not currently gating specific ad features the same way.
TCF v2 interacts with Consent Mode as the standardized vocabulary many European CMPs use to communicate consent choices, and stricter regional privacy frameworks tend to push implementations toward defaulting everything to denied rather than assuming any form of implied consent.
For broader regulatory context beyond Google’s own framework, the Digital Markets Act shapes how large platforms handle data practices across the EU, and it’s worth a read if your compliance team is auditing consent infrastructure holistically rather than tag by tag. If you run ads across multiple platforms, it’s also worth checking Microsoft Ads’ own privacy and consent guidance, since cross-platform consent flows don’t automatically sync just because you’ve handled Google’s side correctly.
What Do Hands-On Implementations Teach You About Consent Mode?
The gap between documentation and production is almost always timing. The Consent Initialization trigger exists precisely because tags load asynchronously in the real world, and any implementation that skips it is betting on load order staying consistent across browsers, connection speeds, and cache states. That bet doesn’t pay off reliably.
The most persistent pitfall is the race between your Google tag initializing and your CMP finishing its own load. The fix isn’t clever code. It’s simply re-pushing the CMP’s consent event once GTM confirms it has loaded, so a missed first push doesn’t leave a visitor stuck in an undefined consent state.
If your business depends on accurate conversion tracking for Google Ads, lean toward server-side tagging once your traffic volume justifies the added setup. It centralizes consent enforcement in one place instead of scattering conditional logic across every page.
Pro Tip: Start with a conservative wait_for_update, around 500 to 1000 milliseconds, then lower it once real-world testing shows your CMP consistently responds faster. Guessing low from the start just means data leaks before your consent banner catches up.
Getting this right takes more than reading Google’s documentation once. If your team needs hands-on support wiring consent signals into an Ads or Analytics setup that’s already live, Growthreachmarketing’s SEO and analytics work covers exactly this kind of technical implementation alongside the broader visibility strategy that depends on clean, trustworthy measurement data.

Frequently Asked Questions
Does Consent Mode V2 setup require a CMP, or can I build my own banner?
You need something that emits a dataLayer event with the user’s choice, whether that’s a full CMP or a custom-built banner. Consent Mode itself doesn’t include a banner; it only reacts to whatever consent signal your solution sends it.
What’s the difference between the default and update commands?
The default command sets the starting consent state (typically all denied) before any tag fires. The update command changes that state the instant a real user makes a choice. Both are required; skipping the default leaves a window where tags run with no consent context at all.
Do I need server-side tagging to implement Consent Mode V2 correctly?
No. Client-side implementation with gtag.js or GTM handles the vast majority of use cases. Server-side tagging becomes worthwhile when you need centralized consent enforcement across a high-volume site or more resilient conversion tracking against ad blockers.
How long should wait_for_update be set to?
Google suggests 500 milliseconds as a safe starting point for asynchronous CMPs. Test your actual banner load time and adjust from there rather than guessing.
Is upgrading from Consent Mode V1 to V2 mandatory?
It’s mandatory in practice if you run Google Ads campaigns serving the EEA, Switzerland, or UK and rely on features tied to advertiser-specific modeling. Outside those regions, it’s strongly recommended but not currently gating specific features.
Sources
For exact syntax and edge cases beyond this guide, these resources cover the gaps:
- Install and implement Google Consent Mode (Enzuzo blog)
- Tag Manager consent mode support – Tag Manager Help


