Skip to main content
Back to Guides
Compliance12 min read

How to Debug Consent Mode v2: A Step-by-Step Troubleshooting Guide

A practical, step-by-step guide to diagnosing broken Consent Mode v2 implementations. Learn to decode gcs and gcd parameters, catch race conditions, and fix the issues causing missing conversions and empty audiences.

When Consent Mode v2 Breaks, It Breaks Silently

A broken Consent Mode v2 implementation won't throw errors. Your tags fire, your banner displays, everything looks normal — until you open Google Ads and notice conversions dropped 40%, or your GA4 audiences are half-empty, or modeled data flatlined.

Consent Mode sits between your CMP and Google's tags, translating user choices into signal states. When that translation goes wrong, Google receives the wrong consent state and quietly adjusts its behavior. No errors, no warnings, just degraded data.

This guide walks through a systematic debugging process. If you haven't implemented Consent Mode yet, start with what Google Consent Mode v2 is and the Google's Consent Mode documentation. If you've implemented it and something isn't right, you're in the right place.

Recognizing the Symptoms

Before you start debugging, confirm you actually have a problem. These are the most common symptoms of a broken or misconfigured Consent Mode v2 setup:

  • Missing conversions in Google Ads. Counts drop suddenly, especially in EU markets. Often coincides with a CMP change, GTM update, or Consent Mode implementation date.
  • Empty or shrinking GA4 audiences. Remarketing audiences stop growing. New segments populate far more slowly than traffic levels suggest.
  • No modeled data in GA4. The "Modeled" badge never appears, or modeled conversions show zero — Google isn't receiving the cookieless pings it needs. See how Consent Mode v2 affects GA4 reporting.
  • Google Ads "Consent gaps" warnings. The diagnostics page flags missing or incomplete consent signals.
  • All traffic consented (or all denied). A 100% or 0% consent rate means the CMP isn't communicating with Consent Mode, or defaults are overriding real choices.

If you're seeing any of these, it's time to open DevTools.

Step 1: Inspect the Network Tab for gcs and gcd Parameters

Open DevTools (F12), go to the Network tab, and reload. Filter by collect to find Google Analytics and Ads collection requests (google-analytics.com/g/collect, td.doubleclick.net). In the Payload section, look for two parameters:

  • gcs — Google Consent Status. Encodes the current state of ad_storage and analytics_storage.
  • gcd — Google Consent Data. Encodes all four Consent Mode v2 signals with their derivation history (how the state was set).

What to look for:

  • If gcs and gcd are completely absent, Consent Mode is not active at all. Your gtag('consent', 'default', ...) call isn't firing, or it's firing after the Google tags have already initialized.
  • If gcs shows G100 on every request even after a user clicks accept, the consent update isn't reaching the Google tags.
  • If gcd contains the letter l in any position, that signal hasn't been configured with Consent Mode — your implementation is incomplete.

Capture these parameter values before and after clicking your consent banner's accept button. The values should change. If they don't, the update command isn't firing correctly.

Step 2: Decode the gcs Parameter

The gcs parameter follows a simple format: G1XY, where X represents ad_storage and Y represents analytics_storage.

gcs Parameter Values
gcs Valuead_storageanalytics_storageMeaning
G100DeniedDeniedNo consent granted
G110GrantedDeniedAd cookies only
G101DeniedGrantedAnalytics cookies only
G111GrantedGrantedFull consent

Important: gcs only encodes two of the four Consent Mode v2 signals. The other two — ad_user_data and ad_personalization — are carried exclusively in the gcd parameter. If you're debugging issues with Google Ads audience building or remarketing, gcs alone won't tell you enough; you need to decode gcd as well.

The expected behavior: before the user interacts with your banner, gcs should reflect your default consent state (typically G100 in EU regions). After the user accepts, it should change to G111. If gcs never changes, your gtag('consent', 'update', ...) call isn't working.

Step 3: Decode the gcd Parameter

The gcd parameter is more complex. It encodes all four Consent Mode v2 signals along with information about how each signal's state was derived — whether it came from a default setting, a user action, or both.

The format is: 11[ad_storage]1[analytics_storage]1[ad_user_data]1[ad_personalization]5

The string starts with 11, uses 1 as a separator between signals, and ends with 5. Each signal position contains a single letter that encodes both the default state and the update state (if any). For a full technical reference, see Simo Ahava's Consent Mode v2 deep dive.

gcd Letter Codes
LetterDefault StateUpdate StateWhat It Means
lNot setNot setSignal not configured — broken implementation
mNot setDeniedNo default; user denied after interaction
nNot setGrantedNo default; user granted after interaction
pDeniedNo updateDenied by default, user hasn't interacted
qDeniedDeniedDenied by default, user clicked decline
rDeniedGrantedDenied by default, user accepted — ideal EU flow
tGrantedNo updateGranted by default, user hasn't interacted
uGrantedDeniedGranted by default, user withdrew consent
vGrantedGrantedGranted by default, user confirmed consent

Example: gcd=11p1p1p1p5 means all four signals are denied by default and the user hasn't interacted yet — the expected pre-consent state for a GDPR-region visitor.

Example: gcd=11r1r1r1r5 means all four signals were denied by default and then granted after the user clicked accept — the expected post-consent state.

Red flag: l in any position (e.g. gcd=11l1l1p1p5) means those signals aren't configured — common when a v1 setup hasn't added the two v2 signals. See why Consent Mode v2 setups fail compliance checks for common errors.

Step 4: Use GTM Preview Mode to Inspect Consent State

If you use Google Tag Manager, Preview mode gives you a real-time view of consent state. Open GTM, click Preview, enter your site URL, and check the Tag Assistant panel.

  1. Click the "Consent" tab. This shows all consent signal states at the time of each event.
  2. Check initialization. The first event should show default consent states for all four signals.
  3. Interact with the banner. A "Consent Update" event should appear. Verify the states changed correctly.
  4. Check tag firing. Click any fired tag and look for its "Consent" section — it shows which consent types the tag requires.

What to look for:

  • Empty Consent tab = no consent configuration in your GTM container.
  • Defaults appear but no update event = CMP callback to GTM is broken.
  • Only 2 of 4 signals present = v1 implementation not upgraded. This is the most common issue. See Advanced vs Basic Consent Mode.

Step 5: Check Google Ads Consent Diagnostics

Google Ads has a consent diagnostics page that flags server-side issues invisible to local testing.

  1. Navigate to Tools → Data manager → Diagnostics.
  2. Check the "Consent gaps" section — the percentage of traffic with incomplete signals.
  3. Look for "Consent Mode not detected" warnings.
  4. Review the signal coverage report for each of the four consent signals.

This report aggregates data across all your traffic, catching issues you'd miss testing a single browser. A consent gap above 10-15% indicates a systemic problem.

Common findings:

  • High consent gap: CMP isn't loading on all pages, or some pages lack consent defaults.
  • "ad_user_data not detected": Legacy v1 implementation missing the v2 signals.
  • Declining coverage over time: A CMP or GTM change broke something. Cross-reference the decline date with your change history.

Step 6: Verify Default Timing — Does It Fire Before Tags?

This is where most implementations silently break. gtag('consent', 'default', ...) must execute before any Google tag fires. If a tag fires first, it sends data without consent signals.

How to verify:

  1. In DevTools Console, confirm when your consent default code executes.
  2. In the Network tab, check whether collect requests appear before the default has fired.

In GTM:

  • The consent default tag must fire on "Consent Initialization - All Pages" — this fires before all other triggers including "All Pages."
  • If it uses "All Pages" or "DOM Ready" instead, it's too late.
  • In GTM Preview, the consent default should be the first timeline item. If "Page View" appears before it, your sequencing is wrong.

See GTM and Consent: the complete setup guide for correct trigger configuration.

Step 7: Check for Race Conditions Between CMP and GTM

Race conditions are the most frustrating Consent Mode bugs because they're intermittent. Everything works in your testing, but real-world users on slower connections hit a different execution order.

The typical race condition:

  1. GTM container loads and fires tags.
  2. CMP script loads slightly later (different CDN, larger file).
  3. CMP sets consent defaults — but tags already fired without consent signals.

How to detect race conditions:

  • Throttle your network. In DevTools Network tab, select "Slow 3G" and reload. Watch whether Google tags fire before the CMP loads. On fast connections the CMP wins the race; on slow ones, it might not.
  • Check consent gap trends. Race conditions cause fluctuating coverage. If Google Ads diagnostics show a gap swinging between 5% and 30%, a race condition is likely.
  • Check gcd on initial page load. If the first collect request shows l values but subsequent requests are correct, the consent default arrived late.

How to fix race conditions:

  • Place your CMP script before the GTM snippet in your HTML <head>.
  • Use GTM's "Consent Initialization" trigger (not "All Pages") for your consent default tag.
  • If your CMP sets defaults via its own script, ensure it's synchronous or completes before GTM loads. Async CMP loaders are the number one cause of consent race conditions.
  • Use the wait_for_update parameter: setting wait_for_update: 500 tells Google tags to wait up to 500ms for a consent update before firing with defaults.

Step 8: Verify All Four Signals Update on Consent Change

Many implementations only update ad_storage and analytics_storage, leaving ad_user_data and ad_personalization stuck in their default state.

How to verify:

  1. Clear cookies and reload (simulate a new visitor).
  2. Open DevTools Network tab, filter for collect.
  3. Before banner interaction, check gcd. All four positions should show a default letter (p in EU, t outside EU).
  4. Click "Accept All."
  5. Check gcd on the next request. All four should show an updated letter (r for denied-to-granted, v for granted-to-granted).

What a correct transition looks like:

Consent Signal Transition (EU Accept All)
SignalBefore ConsentAfter Accept Allgcd Letter Change
ad_storagedeniedgrantedp → r
analytics_storagedeniedgrantedp → r
ad_user_datadeniedgrantedp → r
ad_personalizationdeniedgrantedp → r

If ad_user_data and ad_personalization stay at p after the user accepts, your gtag('consent', 'update', ...) call is only setting two signals. Update it to include all four:

gtag('consent', 'update', {
  ad_storage: 'granted',
  analytics_storage: 'granted',
  ad_user_data: 'granted',
  ad_personalization: 'granted'
});
Copy code to clipboard

Troubleshooting Flowchart: Symptom to Fix

Use this as a quick reference when you've identified a symptom but aren't sure where to look first.

Symptom → Cause → Fix
SymptomLikely CauseWhere to CheckFix
No gcs/gcd paramsConsent Mode not implementedNetwork tab → filter collectAdd gtag consent default before tags load
gcd contains lSignal not configuredgcd parameterAdd missing signals to default and update
gcs stuck at G100Update not firingGTM Preview → Consent tabFix CMP callback; ensure update fires on accept
All traffic G111Default set to grantedGTM Preview → first eventSet default to denied for EU
No modeled data in GA4Basic mode or broken AdvancedGA4 reports → Modeled badgeSwitch to Advanced mode; fix default timing
Intermittent consent gapsCMP/GTM race conditionAds diagnostics; Slow 3G testCMP before GTM; Consent Init trigger; wait_for_update
Only 2 of 4 signalsLegacy v1 setupgcd showing lAdd ad_user_data + ad_personalization
Correct state, low conversionsTag needs extra consent typesGTM tag detailsCheck Additional Consent settings
Different behavior per pageInconsistent configCompare gcd across pagesLoad CMP + defaults on every page

How CookieBeam Simplifies Consent Mode Debugging

The debugging steps above work, but they're manual, repetitive, and easy to get wrong — especially on sites with multiple GTM containers, regional consent rules, or dozens of tags. CookieBeam's consent diagnostics are designed to replace that manual work.

Automatic signal validation. CookieBeam validates that all four Consent Mode v2 signals are present in your default and update commands before publishing. If ad_user_data or ad_personalization are missing, you see the error in the dashboard — not weeks later in a Google Ads consent gap report.

Timing verification. CookieBeam fires consent defaults synchronously before any Google tag can initialize, eliminating the race conditions described in Step 7. The consent default is embedded in the loader itself, not loaded as a separate async script.

Real-time consent state monitoring. The dashboard shows live consent state data across your traffic — what percentage of visitors have each signal granted, denied, or in default state. Instead of decoding gcd strings one request at a time, you get an aggregate view of signal health.

Regional consent rules. CookieBeam's regional consent system sets the right defaults per visitor location automatically — denied-by-default for GDPR regions, granted-by-default where appropriate.

Cross-domain consistency. CookieBeam's cross-domain consent sharing ensures the same consent state applies everywhere, preventing the "works on the main site but not on the checkout subdomain" scenario.

You should understand what gcd=11p1p1l1l5 means — that understanding tells you exactly what's broken. But the goal is a setup where you never have to decode those strings in the first place.

How to Debug Consent Mode v2: Step-by-Step Troubleshooting Guide | CookieBeam | CookieBeam