Google Ads and GA4 report that Consent Mode v2 signals are missing — remarketing audiences stop populating and Tag Assistant flags the consent state as incomplete — because the CMP you chose emits the two legacy signals but not the two v2 signals ad_user_data and ad_personalization.

Triage: Confirming the Missing v2 Signals

Work through these checks before changing any configuration. The goal is to prove the CMP is the source of the gap, not GTM or the tag itself.

  1. Open GA4 DebugView or Tag Assistant. Load the site in a fresh session with storage cleared. Trigger the consent banner and accept all.

  2. Inspect the consent state event. In Tag Assistant, click the consent update event. A correct v2 implementation shows four rows: ad_storage, analytics_storage, ad_user_data, ad_personalization. If only the first two are present, the CMP is emitting a Consent Mode v1 payload.

  3. Read the live state from the console. Google exposes the resolved consent state internally; the fastest external check is to inspect the dataLayer for the consent commands:

    // List every consent command the page pushed, in order.
    window.dataLayer
      .filter((e) => Array.isArray(e) && e[0] === 'consent')
      .forEach((e) => console.log(e[1], e[2]));

    A healthy trace shows a default with all four keys set to denied, then an update with the four keys reflecting the user’s choice. Missing ad_user_data/ad_personalization in either call confirms the defect.

  4. Run the reproduction checklist:

The four v2 signals are not interchangeable, and the two added in v2 are the two most often missing — a platform upgraded from v1 emits a structurally valid call that Google’s tags treat as incomplete.

Two signals carried over, two added — and the new two are the gap Four named signals in two groups. Carried over from version one: analytics storage, which governs measurement cookies, and ad storage, which governs advertising cookies. Added in version two: ad user data, which governs sending user data to Google for advertising, and ad personalisation, which governs remarketing. A note records that a platform emitting only the first two produces a call that looks correct in the data layer but leaves Google's tags treating advertising consent as unspecified. carried over from v1 analytics_storage measurement cookies ad_storage advertising cookies added in v2 — the usual gap ad_user_data sending user data to Google for ads ad_personalization remarketing and audience building Omit the right-hand pair and the call still looks valid in the data layer — nothing warns you. Downstream, advertising consent is treated as unspecified, and modelled conversions degrade quietly.

Because there is no error, the gap is usually discovered in a reporting review weeks later rather than in testing. Make the four-signal assertion part of your release checks: a browser test that reads the data layer after acceptance and fails when fewer than four keys are present costs almost nothing and catches every regression of this shape.

Root Cause: CMP Emits v1 Signals or Fires update() Too Late

Google Consent Mode v2 became mandatory in March 2024 for advertisers serving EEA users through Google’s advertising products. Version 2 added two signals on top of the original set:

  • ad_user_data — governs whether user data may be sent to Google for advertising purposes at all.
  • ad_personalization — governs whether that data may be used for personalized advertising (remarketing, similar audiences).

A CMP built for the original Consent Mode only writes ad_storage, analytics_storage, functionality_storage, personalization_storage, and security_storage. Google’s newer tags read ad_user_data/ad_personalization and, finding them undefined, withhold data from advertising features even when the user consented. The remarketing audience simply stops growing.

There are two distinct failure shapes. The first is a missing-signal defect: the CMP template predates v2 and never writes the two new keys. The second is a timing defect: the CMP writes all four keys but calls update() after the Google tag has already read the default state, so the tag operates on stale denied values. Both surface identically in Tag Assistant, which is why the triage above distinguishes them by checking command order in the dataLayer, not just presence.

Selecting a CMP for Consent Mode v2 therefore reduces to three hard requirements. The CMP must (1) write all four signals in both default and update, (2) emit the default synchronously before the Google tag loads, and (3) integrate through Google’s certified CMP partner program or a maintained template so signal names stay in sync as Google evolves them. This sits under the broader guidance on selecting and integrating a consent management platform, which is the governing reference for the source-of-truth architecture this fix plugs into.

Note the relationship to basic vs advanced Consent Mode. In basic mode the Google tags do not load until consent is granted, so the default denied state simply prevents loading. In advanced mode the tags load immediately and send cookieless, anonymized pings under the denied default, then upgrade on update. Advanced mode is what feeds Google’s conversion modeling — but it only works if the four v2 signals are present in the default, because the modeled pings are tagged with the consent state at send time.

Resolution: Emit All Four Signals in the Correct Order

The minimal fix has two halves: a hardcoded default you control directly in <head>, and a CMP update that carries all four signals. Do not rely on the CMP for the default if you can set it yourself — owning the default guarantees signal completeness and correct ordering regardless of CMP quirks.

<!-- head: BEFORE the CMP bundle and BEFORE gtm.js / gtag.js -->
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag() { dataLayer.push(arguments); }

  // Consent Mode v2 default: all four ad/analytics signals denied.
  // Omitting ad_user_data or ad_personalization here is the exact bug
  // that stops remarketing audiences from populating.
  gtag('consent', 'default', {
    ad_storage: 'denied',
    analytics_storage: 'denied',
    ad_user_data: 'denied',        // v2 — required
    ad_personalization: 'denied',  // v2 — required
    functionality_storage: 'granted',
    security_storage: 'granted',
    wait_for_update: 500 // ms Google waits for update() before acting on default
  });
</script>

<!-- then the CMP bundle, then the Google tag -->

When the user answers the banner, translate the CMP’s choice into a single update carrying all four signals. Drive it from the one place that reads the CMP, so the mapping lives in exactly one module:

// Called from your CMP adapter on every resolved consent change.
function pushConsentModeV2(choice) {
  // choice is your normalized object: { analytics, ads } booleans.
  // Map both v2 ad signals off the advertising consent, and analytics
  // off the analytics consent. Keep the update atomic — one call, four keys.
  gtag('consent', 'update', {
    analytics_storage: choice.analytics ? 'granted' : 'denied',
    ad_storage:        choice.ads ? 'granted' : 'denied',
    ad_user_data:      choice.ads ? 'granted' : 'denied',
    ad_personalization: choice.ads ? 'granted' : 'denied'
  });
}

// TCF v2.2 CMP: derive the choice, then push. Only act on resolved states.
window.__tcfapi('addEventListener', 2, (tcData, ok) => {
  if (!ok) return;
  if (tcData.eventStatus !== 'tcloaded' && tcData.eventStatus !== 'useractioncomplete') return;
  const p = tcData.purpose.consents;
  pushConsentModeV2({
    analytics: p[1] === true && p[8] === true,       // store + measure content
    ads: p[1] === true && p[3] === true && p[4] === true // store + create/select ads profile
  });
});

If you use a certified CMP template (OneTrust’s or Cookiebot’s Consent Mode v2 build), the vendor emits these calls for you — your selection criterion is simply to confirm the template is the v2 version and that it is configured to fire the update from the same purpose mapping. Do not run both your own update and the CMP’s; pick one owner for the mapping.

Reading the signals back out

Verification is a matter of reading the same four keys the tags read, at the two moments that matter. Both reads have a distinct expected shape, and a platform that is subtly wrong will produce a plausible-looking value at one of them.

Two reads, two expected shapes Two verification points. At the default call, all four signals must read denied and all four keys must be present; a platform emitting only two keys, or emitting granted defaults, fails here. After the update call, the four signals must reflect the visitor's actual choice and the update must arrive within the consent-to-execution budget; a platform that fires the update before the visitor answered, or that omits the two version-two keys from the update, fails here. read 1 · at the default call 4 keys present, all "denied" fails if only 2 keys appear fails if any default is "granted" catches a platform still emitting v1 read 2 · after the update call 4 keys, matching the actual choice fails if the update fired unprompted fails if the v2 keys are dropped here catches an update that races the banner Assert both in a browser test. A platform can pass either read alone while still being wrong. Time the gap between the two reads as well — it is your consent-to-execution budget.

Verification

Reload with storage cleared, open GA4 DebugView, and accept all consent. In the consent state panel the four signals must read: analytics_storage: granted, ad_storage: granted, ad_user_data: granted, ad_personalization: granted. Then reload and reject: all four must read denied. The single decisive check is that ad_user_data and ad_personalization appear and change — their presence and correct toggling is what Google Ads reads to resume audience collection. Within 24–48 hours, the Google Ads audience that had plateaued should resume growing.

Order is part of the contract

The two calls have to happen in a fixed order relative to the container, and the window between them is where every remaining defect lives. The default call must precede the container; the update call must follow the decision; and nothing in between may assume a resolved state.

The two calls, and what sits between them A four-step ordering. The consent default call runs inline before anything else and establishes denied values for all four signals. The tag container then loads and boots against those defaults. The visitor makes a decision. The consent update call then runs with the resolved values, releasing held tags. A note records that the region between the default and the update is the modelling window, during which Google tags may send cookieless pings if advanced mode is enabled. consent default inline, all four denied container loads boots against the defaults visitor decides may never happen consent update held tags released the modelling window In advanced mode, cookieless pings are sent inside this window. In basic mode, nothing is. Which of the two you run is a compliance decision, not a performance one — get it signed off. A visitor who never answers stays in this window for the whole session, at the denied defaults.

Common Pitfalls

  • Setting the default after the CMP loads. If the default command is not synchronous in <head> before the Google tag, the tag reads an undefined state and assumes granted, firing pre-consent. The default must be the first dataLayer push.
  • Mapping only ad_storage from the ads choice and leaving the two v2 signals denied. All three advertising signals (ad_storage, ad_user_data, ad_personalization) should derive from the same advertising consent unless your legal basis deliberately splits them. Leaving the v2 pair hardwired to denied silently kills remarketing.
  • Running two owners of the update call. A hand-rolled update plus the CMP template’s update race each other; the loser overwrites the winner. Pick one owner, as covered in the CMP integration guide.

Frequently Asked Questions

Does Consent Mode v2 replace a TCF integration?

No — they answer to different consumers and both may be required at once. Consent Mode is what Google’s own tags read; the TCF string is what IAB-registered vendors in a programmatic auction read. A publisher selling inventory through those vendors needs both, emitted from the same decision, and a site running only Google properties needs only the former.

Treat them as two outputs of one adapter rather than two integrations. Deriving both from a single normalised consent object is what keeps them from drifting apart, which is the failure that produces a visitor consented in one framework and refused in the other.

What should the four signals default to for a visitor outside the EEA?

That depends on which regime applies, and it is the reason the default call should be built from the resolved region rather than hard-coded. Under an opt-out regime the defaults can legitimately be granted, and forcing denied there loses measurement you were entitled to collect. Under an opt-in regime they must be denied.

Because the default call has to run inline before the container, the region has to be known at that moment — which in practice means it comes from the edge, injected into the document, rather than from a client-side lookup that resolves after the container has already booted.


Up: Selecting and Integrating a Consent Management Platform