Consent Mode v2
Complete implementation guide for Google Consent Mode v2, required for EU/EEA advertisers from March 2024.
What's New in v2
Additional Parameters
Consent Mode v2 introduces two new parameters:
| Parameter | Purpose | Required | |-----------|---------|----------| | ad_user_data | Consent to send user data to Google for ads | Yes (EEA) | | ad_personalization | Consent for personalized advertising | Yes (EEA) |
Complete Parameter Set
gtag('consent', 'default', {
'ad_storage': 'denied', // Advertising cookies
'analytics_storage': 'denied', // Analytics cookies
'ad_user_data': 'denied', // NEW: User data for ads
'ad_personalization': 'denied', // NEW: Personalized ads
'wait_for_update': 500 // Wait for CMP
});
Why It Matters
EEA Requirements
Starting March 2024, for EEA users:
- Google Ads: Cannot use audience lists without
ad_user_dataconsent - Remarketing: Cannot personalize without
ad_personalizationconsent - Conversion tracking: Limited without proper consent signals
Impact Without v2
| Feature | Without v2 | With v2 | |---------|-----------|---------| | Remarketing lists | Disabled | Works with consent | | Customer Match | Disabled | Works with consent | | Conversion modeling | Limited | Full capability | | Bid optimization | Impaired | Full functionality |
Implementation Guide
Step 1: Set Default State
Place this code before GTM or any Google tags:
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Set default state for all users
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'wait_for_update': 500
});
// For non-EEA users, you might grant by default
// (Check with legal first)
// gtag('consent', 'default', {
// 'ad_storage': 'granted',
// 'analytics_storage': 'granted',
// 'ad_user_data': 'granted',
// 'ad_personalization': 'granted',
// 'region': ['US', 'CA'] // Only for these regions
// });
</script>
Step 2: Update on User Consent
When user grants consent via CMP:
// User accepts all
gtag('consent', 'update', {
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted'
});
// User accepts analytics only
gtag('consent', 'update', {
'analytics_storage': 'granted'
});
// User accepts ads but no personalization
gtag('consent', 'update', {
'ad_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'denied'
});
Step 3: GTM Configuration
In Google Tag Manager:
- Enable Consent Overview: Settings → Container Settings → Enable consent overview
- Configure Google Tag: Built-in consent checks enabled by default
- Set Tag Consent: For each tag, specify required consent
Consent Configuration Per Tag
| Tag Type | Required Consent | |----------|------------------| | GA4 Configuration | analytics_storage | | GA4 Event | analytics_storage | | Google Ads Conversion | ad_storage | | Google Ads Remarketing | ad_storage, ad_personalization | | Floodlight | ad_storage |
CMP Integration
Supported CMPs
These CMPs have built-in Consent Mode v2 support:
| CMP | v2 Support | Integration | |-----|------------|-------------| | Cookiebot | Yes | Automatic via GTM template | | OneTrust | Yes | Manual configuration | | CookieYes | Yes | Built-in | | Usercentrics | Yes | GTM template available | | Iubenda | Yes | Manual configuration | | Termly | Yes | Built-in |
Cookiebot Example
// Cookiebot auto-updates consent via GTM template
// Or manually listen to consent events:
window.addEventListener('CookiebotOnAccept', function() {
gtag('consent', 'update', {
'ad_storage': Cookiebot.consent.marketing ? 'granted' : 'denied',
'analytics_storage': Cookiebot.consent.statistics ? 'granted' : 'denied',
'ad_user_data': Cookiebot.consent.marketing ? 'granted' : 'denied',
'ad_personalization': Cookiebot.consent.marketing ? 'granted' : 'denied'
});
});
OneTrust Example
// Map OneTrust categories to Consent Mode
function updateConsentFromOneTrust() {
const activeGroups = OnetrustActiveGroups || '';
gtag('consent', 'update', {
'analytics_storage': activeGroups.includes('C0002') ? 'granted' : 'denied',
'ad_storage': activeGroups.includes('C0004') ? 'granted' : 'denied',
'ad_user_data': activeGroups.includes('C0004') ? 'granted' : 'denied',
'ad_personalization': activeGroups.includes('C0004') ? 'granted' : 'denied'
});
}
// Listen for OneTrust changes
window.OneTrust?.OnConsentChanged(updateConsentFromOneTrust);
Advanced Configuration
Region-Based Defaults
Apply different defaults by region:
// Strict for EEA
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'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',
'IS', 'LI', 'NO', 'GB']
});
// Less strict for US (opt-out model)
gtag('consent', 'default', {
'ad_storage': 'granted',
'analytics_storage': 'granted',
'ad_user_data': 'granted',
'ad_personalization': 'granted',
'region': ['US']
});
URL Passthrough
Enable conversion linking without cookies:
gtag('set', 'url_passthrough', true);
// Adds gclid/dclid to links when cookies denied
Ads Data Redaction
Redact ad click identifiers when consent denied:
gtag('set', 'ads_data_redaction', true);
// Removes ad identifiers from cookieless pings
Testing & Validation
Preview Mode Checklist
- Consent state visible: Check GTM preview for consent state
- Tags blocked correctly: Verify blocked tags when denied
- Updates propagate: Confirm updates trigger tags
Debug in Console
// Check current consent state
console.log(dataLayer.filter(item =>
item[0] === 'consent'
));
// Monitor consent changes
dataLayer.push = function(original) {
return function(item) {
if (item[0] === 'consent') {
console.log('Consent event:', item);
}
return original.apply(this, arguments);
};
}(dataLayer.push);
Google Tag Assistant
- Install Tag Assistant
- Start recording
- Navigate to your site
- Check consent state indicators
- Verify tag behavior matches consent
Verification Checklist
Technical Validation
- [ ] Default consent set before Google tags
- [ ] All four v2 parameters included
- [ ]
wait_for_updateconfigured - [ ] CMP properly updates consent
- [ ] GTM consent overview enabled
- [ ] Tags have correct consent requirements
Functional Validation
- [ ] No tracking before consent granted
- [ ] Full tracking after consent granted
- [ ] Partial tracking with partial consent
- [ ] Consent persists across sessions
- [ ] Withdrawal stops tracking immediately
Google Ads Validation
- [ ] Conversions still tracked (modeled if denied)
- [ ] Remarketing audiences building (when consented)
- [ ] Customer Match working (when ad_user_data granted)
Common Issues
Consent Not Updating
| Symptom | Cause | Fix | |---------|-------|-----| | Tags still blocked | Update not triggering | Check CMP callback | | Tags fire without consent | Missing default | Add default before GTM | | Inconsistent behavior | Race condition | Increase wait_for_update |
Migration Issues
If migrating from v1:
- Add new parameters to default
- Update CMP mapping
- Test all consent states
- Monitor for conversion drops
Previous: Privacy Overview Next: First-Party Data Strategy