Skip to content
← Back to Blog

The consent gap: Why 'configured' doesn't mean 'correct'

A tag can have consent configured and still be non-compliant. The real problems are type mismatches, missing v2 signals, and CMP timing. Here's what we found when we looked deeper.

A tag can have consent configured and still be non-compliant. The consent type can be wrong. The v2 signals can be missing. The CMP can be loading after tags have already made their decisions. Checking whether consent exists is useful, but it only catches the obvious case: a tag with no consent at all. The subtle problems, which are more common, pass that check and survive in production for months.

The consent gap is the space between "configured" and "correct." Closing it requires checking whether the consent settings match the tag's actual function, whether they include the signals that regulations now require, and whether the consent infrastructure fires in the right order.

GTM consent type mismatches

The most common consent finding in real containers isn't missing consent. It's the wrong consent type.

Ad tags (Google Ads, Microsoft UET, Meta Pixel) should be gated behind ad_storage. GA4 tags should be gated behind analytics_storage. Google's consent mode documentation establishes that baseline. The pattern that shows up repeatedly is ad tags using analytics_storage as their consent type. The cause is usually straightforward: someone configures consent on a GA4 tag, then copies those settings when adding ad tags to the same container.

The result: advertising tags fire when a visitor grants analytics consent but denies ad consent. The visitor made a deliberate choice about advertising tracking, and the container ignores it. Not malicious. Just copied from the wrong template.

The mismatch is hard to catch in the GTM UI because the consent configuration looks correct at a glance. The tag has consent settings. The consent type is a valid option. The problem is that the consent type doesn't match the tag's purpose, and nothing in the interface flags that mismatch. Simo Ahava's consent settings post covers the mechanics of how consent types map to tag categories, and it's worth reading if you're configuring consent for the first time.

Missing Consent Mode v2 signals

Google added two consent types in 2024 as part of Consent Mode v2: ad_user_data and ad_personalization. These exist specifically for Digital Markets Act compliance. Advertising tags that don't check these signals won't process conversion data for visitors in the European Economic Area. Google's documentation is direct about this: without the v2 signals, EEA conversions are silently dropped.

Containers set up before 2024 often have ad tags with correct ad_storage consent but no ad_user_data or ad_personalization checks. Everything works for non-EEA traffic. Tags fire correctly, conversions appear in Google Ads, reporting looks healthy. European conversions just disappear. No error, no warning, no log entry. The only signal is a gap in the data that's easy to attribute to normal regional variation.

A presence check would miss this entirely. The tag has consent configured. The consent type is correct. The configuration just predates a regulatory requirement, and nobody went back to update it.

The double-gate consent problem

GTM has two consent mechanisms that work independently: Built-In consent and Additional consent. Built-In consent is embedded in Google's native tag templates. A Google Ads Conversion tag automatically checks ad_storage, ad_personalization, and ad_user_data before deciding how to behave. These checks are greyed out in the UI. You can't remove them, and they're always active when consent mode is running on the page.

Additional consent is configured by the person managing the container. One option is "Require additional consent for tag to fire," which adds a hard gate on top of whatever the Built-In consent already checks.

The double-gate problem happens when someone adds Additional consent on top of correct Built-In consent, but with a different consent type. A Google Ads tag with Built-In ad_storage and Additional analytics_storage requires a visitor to grant both ad consent and analytics consent before the tag fires. If the visitor grants ad consent but not analytics, the tag stays silent. Conversion data is suppressed for visitors who made a perfectly valid consent choice.

The double-gate is harder to diagnose than a straightforward misconfiguration because both consent mechanisms are doing their job. Built-In consent is checking ad_storage correctly. Additional consent is checking analytics_storage correctly. They're just conflicting with each other, and the combined effect is a tag that fires less often than it should. The suppression looks like normal consent-based data reduction, which makes it easy to overlook.

When the CMP loads too late

Consent settings in GTM are only meaningful if the consent management platform reports the visitor's consent state before tags start making decisions. That timing is controlled by the waitForUpdate setting on the default consent command.

When waitForUpdate is set to 0 (or not set at all), GTM doesn't wait for the CMP. Tags fire immediately using the default consent state, which is typically "denied" for all consent types. If the CMP loads a moment later and the visitor grants consent, the tags have already made their decision. The consent banner appears, the visitor clicks "Accept All," and the tags that already fired in a denied state don't re-evaluate.

In the opposite scenario, if the default consent state is "granted" and the CMP loads late, tags fire with full consent before the visitor has had a chance to make a choice. The banner is cosmetic. It collects a preference that was already overridden by the tag firing sequence.

The waitForUpdate value is a timeout in milliseconds. Google recommends a value that gives the CMP enough time to load and initialize, typically 500ms or higher. A value of 0 means the consent infrastructure is structurally broken regardless of how correctly the individual tags are configured.

How Built-In consent works in GTM

Resolving these findings requires knowing what each tag template enforces natively. A native Google Ads tag with consentStatus: NOT_NEEDED in the container JSON is fine. That value means no Additional consent is required, but the tag's Built-In consent checks are still active. A Custom HTML tag with the same NOT_NEEDED value has no consent gate at all, because Custom HTML templates have no Built-In consent. Same JSON, different meaning.

TagManifest maintains a static Built-In consent map that knows what each tag template enforces. Google Ads templates enforce ad_storage, ad_personalization, and ad_user_data. GA4 templates enforce analytics_storage. LinkedIn Insight, Reddit Pixel, and community templates enforce nothing. With that lookup, every consent finding can be evaluated against what the tag template actually provides, not just what the JSON says.

The early version of the consent audit didn't make this distinction. It read NOT_NEEDED and flagged it as a consent bypass regardless of the tag type. For Custom HTML tags, that's accurate. For native Google tags, it's Google's recommended configuration. The recommendations were too aggressive. Flagging correct setups as problems burned real time on remediation plans that turned out to be wrong. Distinguishing between Built-In and Additional consent made the findings actually useful instead of noisy.

What a container scan doesn't check

TagManifest checks GTM tag consent settings. That's one layer of a larger consent stack.

Your CMP's cookie classification dashboard determines which cookies map to which consent categories. If _ga is classified as "Necessary" in your CMP, GA4 cookies fire regardless of what GTM says. The CMP classification is upstream of GTM in the consent stack, and it can override tag-level settings entirely.

Server-side cookies set in HTTP response headers bypass GTM and the CMP. Third-party scripts loaded outside GTM (hardcoded in page templates, injected by plugins, loaded by embeds) create cookies that no GTM audit can see. These are separate layers that require separate tools and separate checks.

The consent panel in TagManifest includes a scope note that says this explicitly. Consent findings from a container audit are threads to pull, not compliance declarations. The tool is more useful when it's precise about what it covers and direct about what it doesn't.

How to check consent correctness

The consent gap closes when you move from "does consent exist" to "is consent correct." Type correctness, not just presence. V2 signals in place for any tag that processes EEA data. Additional consent reinforcing Built-In consent rather than conflicting with it. And the CMP actually loading before tags make decisions.

Upload your container JSON to TagManifest and check the consent panel. It'll show you which of these problems exist in your container, which tags are affected, and what to investigate further.

Audit your GTM container

TagManifest gives you an instant health score and prioritized fixes.

Scan Your Container