Consent Mode Setup in GTM
Consent Mode configuration in GTM is split between two places: code that runs before GTM loads (setting the default state), and GTM itself (handling the consent update and configuring per-tag consent requirements). Getting the sequencing wrong is the most common implementation mistake.
This article walks through the complete setup in the correct order.
Step 1: Set default consent state before GTM
Section titled “Step 1: Set default consent state before GTM”The default consent state must be set before the GTM snippet. This is non-negotiable. If you set it inside GTM, there is a timing gap where tags may fire without a consent state defined.
Add this code block immediately before your GTM snippet in <head>:
<!-- Consent Mode default — MUST come before GTM snippet --><script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', { 'ad_storage': 'denied', 'analytics_storage': 'denied', 'ad_user_data': 'denied', 'ad_personalization': 'denied', 'functionality_storage': 'denied', 'personalization_storage': 'denied', 'security_storage': 'granted', 'wait_for_update': 500 });</script>
<!-- Google Tag Manager --><script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXX');</script><!-- End Google Tag Manager -->If you operate in both EU and non-EU markets, use regional overrides:
// Default: granted globallygtag('consent', 'default', { 'ad_storage': 'granted', 'analytics_storage': 'granted', 'ad_user_data': 'granted', 'ad_personalization': 'granted', 'security_storage': 'granted'});
// Override: denied for EEA + UKgtag('consent', 'default', { 'ad_storage': 'denied', 'analytics_storage': 'denied', 'ad_user_data': 'denied', 'ad_personalization': 'denied', 'wait_for_update': 500, 'region': ['AT','BE','BG','HR','CY','CZ','DK','EE','FI','FR','DE', 'GR','HU','IE','IT','LV','LT','LU','MT','NL','PL','PT', 'RO','SK','SI','ES','SE','NO','IS','LI','GB']});Step 2: Configure the Consent Initialization trigger
Section titled “Step 2: Configure the Consent Initialization trigger”GTM has three initialization trigger groups that fire in order:
- Consent Initialization — All Pages: fires first, before any tags
- Initialization — All Pages: fires second
- All Pages (Page View): fires third, your normal tags
Your consent default tag (if managed through GTM rather than inline script) must fire on Consent Initialization. Everything else fires after. This trigger is in the Trigger configuration dropdown under “Initialization.”
Step 3: Create the consent update tag
Section titled “Step 3: Create the consent update tag”When your CMP fires a consent update, you need to propagate that update to Google’s Consent Mode system. The mechanism depends on your CMP.
Option A: CMP fires a custom dataLayer event
Section titled “Option A: CMP fires a custom dataLayer event”Many CMPs push a custom event when consent is granted. Create a Custom Event trigger listening for that event, and a tag that calls the consent update:
Trigger: Custom Event, Event Name = consentUpdate (or whatever your CMP pushes)
Tag (Custom HTML):
<script> gtag('consent', 'update', { 'ad_storage': {{DLV - consent.advertising}} === 'true' ? 'granted' : 'denied', 'analytics_storage': {{DLV - consent.analytics}} === 'true' ? 'granted' : 'denied', 'ad_user_data': {{DLV - consent.advertising}} === 'true' ? 'granted' : 'denied', 'ad_personalization': {{DLV - consent.advertising}} === 'true' ? 'granted' : 'denied' });</script>Where {{DLV - consent.advertising}} is a Data Layer Variable reading consent.advertising from the dataLayer push your CMP makes.
Option B: CMP uses its own GTM template
Section titled “Option B: CMP uses its own GTM template”Most major CMPs provide a Community Template Gallery integration that handles the consent update automatically. See CMP Integration for CMP-specific setup instructions.
Option C: CMP exposes a JavaScript callback
Section titled “Option C: CMP exposes a JavaScript callback”If your CMP has a JavaScript API, call the consent update directly from the CMP callback:
// Example: CookieYes callback patterndocument.addEventListener('cookieyes_consent_update', function(evt) { var accepted = evt.detail.accepted || []; gtag('consent', 'update', { 'analytics_storage': accepted.includes('analytics') ? 'granted' : 'denied', 'ad_storage': accepted.includes('advertisement') ? 'granted' : 'denied', 'ad_user_data': accepted.includes('advertisement') ? 'granted' : 'denied', 'ad_personalization': accepted.includes('advertisement') ? 'granted' : 'denied' });});Step 4: Configure consent settings on individual tags
Section titled “Step 4: Configure consent settings on individual tags”Every tag in GTM can have consent requirements configured under Advanced Settings → Consent Settings. This is a per-tag safeguard that prevents a tag from firing even if the consent update mechanism fails.
For each tag, configure:
- Additional consent checks required: select the consent type(s) this tag requires
- GTM will not fire the tag unless all required consent types are
granted
Standard mappings:
- GA4 Configuration and Event tags:
analytics_storage - Google Ads Conversion Tracking:
ad_storage+ad_user_data - Google Ads Remarketing:
ad_storage+ad_personalization - Meta Pixel, LinkedIn, TikTok: use the blocking approach in Consent for Non-Google Tags
Step 5: Handle returning visitors
Section titled “Step 5: Handle returning visitors”Returning visitors have already made a consent choice stored in your CMP’s cookie. Your CMP should read this cookie and fire the consent update immediately — before the wait_for_update timeout expires.
Verify this works correctly:
- Grant consent on a test browser
- Close and reopen the browser
- Visit the site again
- Check that the consent update fires before GTM’s first tag evaluation
If returning visitors trigger the wait_for_update timeout instead of restoring previous consent immediately, your CMP is not reading its stored consent on page load quickly enough. Check your CMP’s consent persistence configuration.
Verifying consent state in Preview mode
Section titled “Verifying consent state in Preview mode”GTM’s Preview mode has a dedicated Consent tab that shows the current consent state at any point in the page lifecycle.
- Open GTM Preview mode and load your site
- Click on any event in the timeline (e.g.,
gtm.js) - Select the Consent tab in the event detail panel
- You will see each consent type and its current state (
granted,denied, orundefined)
What to check:
- On first load (before CMP interaction): all types should be
deniedfor EU users - After accepting all consent: all types should be
granted - After rejecting all consent: advertising types should be
denied, potentially analytics too
If you see undefined for any consent type, your default state is not being set correctly.
The wait_for_update deep dive
Section titled “The wait_for_update deep dive”Understanding exactly what wait_for_update does is important for diagnosing consent timing issues.
When GTM processes a tag that requires consent, it checks the current consent state. If the state for a required type is denied:
- GTM checks whether
wait_for_updateis still active - If active: GTM queues the tag and waits
- When the consent update arrives (or the timeout expires): GTM re-evaluates queued tags
- If consent is now
granted: queued tags fire - If the timeout expires with consent still
denied: tags do not fire (correct behavior)
The timeout clock starts when the gtag('consent', 'default') call is processed. It is a one-time window per page load, not a rolling timer.
What happens when the timeout expires:
- Tags that require denied consent types are silently dropped
- No error is thrown
- Preview mode shows the tag as “not fired” — check the Consent tab to understand why
// Verify consent state programmatically (useful for debugging)// Run in browser console after page loadconsole.log( window.google_tag_data?.ics?.entries);This outputs the current internal consent state object. Each key is a consent type, each value includes the current state and how it was set.
Common mistakes
Section titled “Common mistakes”Forgetting security_storage: 'granted' in the default. Security storage should be granted unconditionally. If you deny it by default and never update it, some Google security features may not function.
Setting consent defaults via the Google Tag in GTM. The Google Tag has a “Set consent defaults” option in its configuration. This fires after GTM loads — too late. Use the inline script approach.
Not testing the consent denial flow. Always test with a fresh private/incognito browser session where no consent cookie exists. The first-visit experience is the most legally sensitive.
Misreading the Preview mode Consent tab. The tab shows the state at the time of the selected event. Click on the consent update event (e.g., consentUpdate) to see the state after it fires, not before.