How the Data Layer and Consent Work Together in GTM

See exactly how the dataLayer array carries Consent Mode signals from your banner to Google tags, with real code and a full page-load example.


by Riad Us Salehin • 5 July 2026


The data layer is a shared JavaScript array, window.dataLayer, that carries messages between your page, your consent management platform, and Google Tag Manager. Consent lives there as four named signals your CMP writes and every Google tag reads before it fires.

Below: the components that carry consent to a tag, how default and update work together, a full example, and where the mechanism trips people up.

How Does Consent Move Through the Data Layer? (The Short Answer)

A CMP writes the visitor's choice into the dataLayer as a Google Consent Mode state: first a default, then an update once the visitor decides. Google tags read that state on every fire. Depending on which signals are granted, a tag sends full data, a cookieless ping, or nothing at all.

Google itself describes the flow in three steps. Set default consent states before any tag fires. Wait for the visitor to interact with the banner, then update the consent state once they choose. By default, every signal is denied unless the site sets its own defaults. Only after the visitor grants consent do Google tags send full measurement data.

This state lives inside the same dataLayer array your other events use, not in a separate consent-only channel. That single-array design is what lets one message bus carry page views, e-commerce events, and consent signals together.

The Components: What Carries Consent From Banner to Tag

Four pieces carry consent from the banner to the tag. The dataLayer array is the transport, gtag() writes to it, the four consent signals are the payload, and GTM's internal consent state reads them.

The dataLayer Array (the Shared Message Bus)

window.dataLayer is one global JavaScript array. Consent messages ride the same array as your page views, clicks, and e-commerce events. There is no separate consent-only channel. A consent management platform writes a consent event into this array the same way it would push any other event.

Three independent CMP vendors document the identical pattern. Consentmo pushes a consent_status event, Pandectes pushes a custom cookie-consent event, and OneTrust fires a consent event whenever a visitor grants or revokes permission. This is the standard way a CMP signals a consent change, not a vendor-specific trick.

The gtag() Shim and the consent Command

gtag() is a thin function. Its entire body is function gtag(){dataLayer.push(arguments);}. Every call to gtag('consent', 'default', {...}) or gtag('consent', 'update', {...}) is really a dataLayer.push() call, formatted as a special entry Google tags know how to interpret.

``javascript function gtag(){dataLayer.push(arguments);} gtag('consent', 'default', { 'ad_storage': 'denied', 'analytics_storage': 'denied', 'ad_user_data': 'denied', 'ad_personalization': 'denied', 'wait_for_update': 500 }); ``

This is why "gtag consent" and "the data layer" are not two systems. They are one pipe: gtag is the syntax, the data layer is the transport.

The Four Consent Signals (What Actually Gets Stored)

Google Consent Mode stores four named signals, each set to granted or denied.

  • ad_storage: advertising cookies and storage
  • analytics_storage: analytics cookies
  • ad_user_data: sending user data to Google for advertising
  • ad_personalization: personalized advertising

Read how each signal behaves when granted or denied on the ad_storage and analytics_storage explainer.

GTM's Built-In Consent State (Not the Same as a Data Layer Variable)

GTM keeps its own internal consent state, separate from any Data Layer Variable you might create to read a consent field. Tags with built-in consent checks read that internal state directly and self-adjust their behavior.

A Data Layer Variable, by contrast, just reads whatever value sits in a dataLayer key at that moment. It does not feed GTM's actual consent engine, and that distinction is the root of the most common Consent Mode mistake, covered below.

How the Pieces Work Together: Default, Then Update

Consent is a two-phase state: a default set before anything fires, then an update once the visitor makes a choice.

The default Command: Consent State Before the Visitor Chooses

gtag('consent', 'default', {...}) runs before the GTM container evaluates any tag's consent requirement. It usually sets every signal to denied and establishes the baseline every tag reads on its first fire.

``javascript gtag('consent', 'default', { 'ad_storage': 'denied', 'analytics_storage': 'denied', 'ad_user_data': 'denied', 'ad_personalization': 'denied', 'wait_for_update': 500 }); ``

wait_for_update: 500 tells Google tags to hold for up to 500 milliseconds before sending any data. That buffer gives an asynchronous CMP time to check for a saved preference. It can then call the update command before the first tag fires on the denied default.

The update Command: Rewriting the State After the Choice

When the visitor accepts, the CMP calls gtag('consent', 'update', {...granted values...}). This rewrites GTM's internal consent state. Google tags re-read the new state: in advanced mode they adjust and start sending full data. In basic mode they fire for the first time, since they were held back entirely until now.

Why gtag('consent','update') and a Custom dataLayer.push Are Not Interchangeable

I hit this exact confusion while wiring a CMP into a client's container. A custom dataLayer.push({event: 'consent_update', ad_storage: 'granted'}) does not change GTM's built-in consent state. Only gtag('consent', 'update', {...}), or GTM's own template APIs (setDefaultConsentState and updateConsentState), actually rewrite what GTM's consent engine checks.

A custom event can still fire a custom trigger you build yourself, that part works fine. What it cannot do is satisfy a tag's built-in consent check or an "additional consent check" requirement.

GTM's consent evaluation is wired specifically to the consent commands, not to an arbitrary event name. If Google tags keep firing, or stay blocked, despite your custom dataLayer push, this mismatch is almost always why.

How a Tag Reads Consent State on a Real Page Load (End to End)

Here is the full mechanism on one page, with GA4, Google Ads, and a Meta Pixel all installed through GTM.

A visitor lands on the page. The CMP's default command fires first, denying all four signals with a 500ms wait. GA4 evaluates its built-in consent check and finds analytics_storage denied.

It sends a cookieless ping instead of a full hit, tagged with a gcs value of G100, meaning nothing granted. Google Ads behaves the same way for its conversion signals.

The Meta Pixel has an additional consent check configured for ad_storage, so it does not fire at all. Meta has no built-in consent-mode awareness of its own.

The visitor clicks Accept. The CMP calls gtag('consent', 'update', {'ad_storage': 'granted', 'analytics_storage': 'granted', 'ad_user_data': 'granted', 'ad_personalization': 'granted'}), and it also pushes a consent_update custom event for any non-Google tags that listen for it.

GA4 re-reads the new state and switches to full, cookie-based measurement for the rest of the session, now sending hits with gcs=G111. The earlier cookieless G100 ping is not deleted. It already fed Google's conversion-modeling pipeline as an anonymized signal, separate from the fully consented data now flowing.

The Meta Pixel's additional consent check now passes on the ad_storage: granted state, so it fires for the first time this session.

How Tags Are Sequenced to Wait for Consent

Tags are held back two ways: Google's native consent checks, and load-order sequencing that guarantees a default exists before anything reads it.

Built-In Consent Checks vs Additional Consent Checks (Advanced vs Basic)

Built-in consent checks alone is advanced mode. GA4, Google Ads, Floodlight, and the Conversion Linker have consent awareness built in, so they fire immediately. Based on the current state, each sends full data, a cookieless ping, or nothing.

Adding a required consent type under "Require additional consent for tag to fire" is basic mode. The tag is withheld entirely until every specified consent type shows granted.

Non-Google tags like the Meta Pixel have no built-in consent logic of their own. An additional consent check is mandatory to gate them at all. Read the full comparison of basic and advanced Consent Mode for which one fits a given setup.

The Consent Initialization Trigger and Load Order

Consent code has to fire on GTM's Consent Initialization trigger, the earliest point in the container, before any normal tag or trigger runs. Google Tag Manager guarantees this trigger fires before all other tags, including other Initialization tags.

That guarantee is what makes a default consent state exist before any tag can possibly read it. This is the mechanism, not the click-by-click setup. For the full configuration walkthrough, see how to set up cookie consent in GTM step by step.

wait_for_update and the Timing Window

wait_for_update holds Google tags for a set number of milliseconds, commonly 500, before they act on the default state. That window exists because a CMP often needs to check a saved cookie or make an async call before it knows whether to call update.

Without the buffer, a fast page load can fire tags on the denied default a beat before the CMP even has a chance to run.

Where Consent Data Layer Behavior Trips People Up

Four assumptions cause most of the real-world confusion developers run into:

  • A custom dataLayer event alone updates GTM's consent state: false. Only the dedicated consent commands (gtag('consent','update',...) or GTM's updateConsentState) rewrite what GTM's consent engine checks. A custom event can drive a custom trigger, nothing more.
  • Re-firing the page_view after consent fixes missing data: it corrupts it instead. Sending the same action twice, once before and once after the banner interaction, produces not-set or duplicated values instead of filling a gap.
  • "A tag read consent state before a default was set" means broken code: usually not. It typically means a load-order race, where something evaluated consent before the Consent Initialization trigger ran. Fixing the sequencing, firing consent first, resolves it.
  • The data layer permanently stores consent: false. The dataLayer is a per-page-load state that gets re-established on every new page. Persisting the visitor's choice across visits is the CMP's job, typically via its own cookie, not the data layer's.

FAQs

Is consent stored in the same dataLayer array as my other events?

Yes. One window.dataLayer array carries consent alongside your page views, clicks, and e-commerce events. There is no separate consent-only array.

Does a custom dataLayer.push event update GTM's consent state?

No. Only gtag('consent', 'update', {...}), or GTM's updateConsentState API, changes GTM's internal consent state. A custom event can fire a custom trigger you build, but it cannot satisfy a built-in or additional consent check.

What causes "A tag read consent state before a default was set"?

A tag or variable evaluated consent before the default command ran, a load-order race. Fix it by firing consent code on GTM's Consent Initialization trigger, which always runs before other tags.

Do I have to write gtag('consent',...) code myself?

No. A certified CMP sets the four defaults and sends the update command automatically when the visitor chooses. There is no hand-written consent code to write or maintain.

What is the difference between built-in consent checks and additional consent checks?

Built-in checks let Google tags like GA4 and Google Ads self-adjust automatically (advanced mode). Additional consent checks withhold a tag entirely until a specified consent type is granted. They are required to gate non-Google tags like the Meta Pixel.

Should I re-fire the GA4 page_view after the visitor accepts?

No. Re-firing corrupts the data with duplicate or not-set values. In advanced mode, GA4 automatically switches to full measurement once consent updates; in basic mode, fire the page_view once, after consent is granted.

Can I read the consent signals in a Data Layer Variable?

You can read whatever consent field a CMP pushes into a Data Layer Variable, but that variable is separate from GTM's actual built-in consent state. Gate tags with built-in or additional consent checks, not a Data Layer Variable condition.

Does the data layer send consent to non-Google tags like Meta?

Not automatically. Non-Google tags do not read Consent Mode signals on their own. Gate them with an additional consent check or a custom trigger tied to the CMP's consent-update event.

Understanding how consent moves from banner to tag through the data layer is the groundwork for wiring it correctly the first time. Consently's Google Consent Mode support sets the four defaults and sends the update automatically, so there is no hand-written gtag('consent') code to maintain. Start a free trial to see the wiring run on your own site.

AUTHOR

Riad Us Salehin is the content lead at Dorik. He is a passionate content creator who lets the work speak for itself. Focused on taking brands and causes to the next level.

Read More

Subscribe to Consently
Newsletter

Subscribe to our newsletter to stay updated with latest articles from our blog.

Built with ❤️ by the team @ Dorik.com 

GET IN TOUCH

Any questions? Feel free to chat with us or reach out to us at

For any queries:
support@consently.net

Follow us:


©2026 Dorik, Inc. All rights reserved.