Skip to content
← Back to Blog

What Consent Looks Like Inside GTM Containers

Native Google tag templates enforce consent at 100%. Custom HTML sits at 24%. The gap isn't negligence. It's architectural: templates enforce consent at setup, Custom HTML doesn't.

What Consent Looks Like Inside GTM Containers

Consent in a GTM container has two layers that operate independently. The first layer is the tag's own consent configuration: the consent types required for the tag to fire (ad_storage, analytics_storage, ad_user_data, ad_personalization). The second layer is whatever consent mechanism exists on the page: a CMP script that sets consent state before or during page load, potentially outside GTM entirely.

Most consent discussions focus on the CMP: which platform, how it's configured, whether it meets regulatory requirements. But the tag-level layer is where the structural gap lives, and it's visible from inside the container without any page-level context.

The structural split

Every native Google tag template in GTM requires consent configuration during setup. When you create a GA4 Event tag, a Google Ads Conversion tag, a Conversion Linker, a Microsoft UET tag, a Floodlight counter, or a LinkedIn Insight tag, the tag template includes a consent settings field. You configure which consent types the tag requires, and GTM evaluates those requirements against the consent state before allowing the tag to fire.

This is template-level enforcement. It's not optional, and it doesn't depend on the person configuring the tag remembering to add consent. The template won't save without a consent configuration. The result is predictable: across containers of every size and complexity, native Google tag templates show 100% consent configuration. Not because every GTM practitioner is consent-aware, but because the template requires it.

Custom HTML tags have no such enforcement. A Custom HTML tag is a blank JavaScript editor with an optional consent settings section that defaults to NOT_SET. NOT_SET means the tag fires regardless of consent state. There's no prompt, no warning, and no requirement to configure consent before saving. The consent section exists, but it requires the person creating the tag to know it's there, understand what it does, and configure it correctly.

The result: across containers in the field, roughly 24% of Custom HTML tags have consent configured. The other 76% fire unconditionally unless something else (a CMP blocking at the page level, a trigger condition checking consent state) prevents them.

What NOT_SET means and doesn't mean

A Custom HTML tag with consent set to NOT_SET is not necessarily non-compliant. NOT_SET means GTM will fire the tag without checking consent state. Whether that matters depends on what else is in the stack.

If a CMP on the page blocks all JavaScript execution until consent is granted (some CMPs do this by preventing GTM from loading at all until the user accepts), then the Custom HTML tag's consent setting is irrelevant. The CMP handles enforcement upstream. The tag fires when GTM fires, and GTM only fires after consent.

If the CMP uses Google Consent Mode to communicate consent state to GTM, then tags with consent set to NEEDED respect that state. Tags with consent set to NOT_SET ignore it. The CMP has done its job (setting the consent state), but the tag doesn't check the state because it wasn't configured to.

If no CMP exists, NOT_SET and NEEDED produce different behavior only for native tags with built-in consent (GA4, Google Ads, Conversion Linker). These tags check consent state automatically through their template code. When no consent state is set, they treat it as "granted" and fire. Custom HTML tags with NOT_SET also fire, but without any consent check at all.

The practical question for any container is: which Custom HTML tags fire and what do they do? A Custom HTML utility tag that pushes the page title to the dataLayer has no consent implications regardless of its setting. A Custom HTML Meta Pixel tag that sends user interaction data to Meta's servers has significant consent implications if the user hasn't consented to advertising tracking.

Where consent is deployed

The CMP deployment pattern across B2B SaaS sites follows a consistent structure. Most consent management happens outside GTM.

Major CMPs (OneTrust, Cookiebot, CookieYes, Osano, TrustArc, Usercentrics) deploy via an inline script in the page's <head> section, before GTM loads. This is the recommended deployment approach because the CMP needs to set consent state before any tags fire, and loading the CMP inside GTM means it competes with other tags for initialization timing.

Roughly 15% of containers have a CMP tag detected inside GTM, typically as a Custom HTML tag or a community template. This approach works but depends on the CMP firing on GTM's Consent Initialization trigger, which fires before all other triggers. If the CMP fires on All Pages or DOM Ready instead, there's a window where tags fire before consent state is established.

Some sites implement consent defaults in the page source using gtag('consent', 'default', {...}) before the GTM snippet. This sets the initial consent state (typically all types denied) that tags check when they first fire. When the user interacts with the consent banner, the CMP updates the consent state, and tags that respect consent mode either fire or remain suppressed based on the updated state.

The combination of page-level CMP deployment and gtag('consent', 'default') in the page source is the most architecturally sound approach. Consent state exists before any GTM tag fires, and tags with consent configured check that state before executing. The gap is in Custom HTML tags that don't check the state because their consent setting is NOT_SET.

The Universal Analytics consent problem

A specific category worth calling out: Universal Analytics tags and consent. UA tags that were created before GTM's consent framework existed have no consent settings. They were never updated because they predate the consent UI, and nobody went back to add consent to tags for a property that stopped processing data in July 2023.

The operational question is whether these dead UA tags (sending data to endpoints that discard it) need consent at all. Technically, they make network requests that transmit page URLs, client IDs, and event data. The data is discarded on arrival, but the transmission itself involves sending user-identifying information to Google's servers. Whether this transmission requires consent depends on the jurisdiction and the specific regulatory interpretation.

Practically, the fix is simpler than the legal question: remove the UA tags. They serve no analytical purpose. They predate consent requirements. They consume page resources. Removing them eliminates both the consent question and the dead code problem simultaneously.

What to check in your own container

The consent audit sequence for any container:

Check native tag consent settings. These should all show NEEDED with appropriate consent types (ad_storage and ad_personalization for advertising tags, analytics_storage for analytics tags). If any native tag shows NOT_SET, it was likely created before the template enforced consent settings and should be updated.

Check Custom HTML consent settings. For each Custom HTML tag with NOT_SET, determine what the tag does. Tags that load advertising pixels (fbq(), lintrk(), ttq(), ad measurement scripts) should have consent configured if the site has GDPR or CCPA obligations. Tags that manipulate the DOM, push non-PII data to the dataLayer, or load non-tracking scripts (chat widgets, support tools) may not require consent, depending on the jurisdiction.

Check for a CMP on the page. View the page source and look for CMP vendor scripts (OneTrust, Cookiebot, CookieYes, etc.). Check whether consent defaults are set before GTM loads. If a CMP exists outside GTM, the Custom HTML tags with NOT_SET may still be blocked at the page level, but this requires verification by testing the page with consent denied.

Check consent type correctness. A tag with consent set to NEEDED but the wrong consent types configured (an ad tag requiring only analytics_storage instead of ad_storage) will fire when the user grants analytics consent but not ad consent, which may not match the intended behavior.

The structural split between native templates (100% configured) and Custom HTML (24% configured) is not a measurement error or a sampling artifact. It's the predictable outcome of one system enforcing consent and the other making it optional. Understanding this architecture is the starting point for any consent review inside a GTM container.

See what's in your setup

Enter your URL for a health score, consent check, and prioritized findings.

Scan Now — Free