Not too long ago, Google announced a new consent mode for Google tags. It allows you to build a mechanism where Google’s tags parse, react, and respond to the consent status of your site visitors.

Consent Mode with a custom Google Tag Manager template Consent Mode with a custom Google Tag Manager template

In short, consent mode is a beta feature, which lets you determine whether or not Google’s advertising tags (Ads and Floodlight) and analytics tags (Universal Analytics, App + Web) can utilize browser storage when sending pings to Google’s servers.

This is (somewhat) in line with, for example, the General Data Protection Regulation (GDPR) and the ePrivacy Directive (ePD) in the European Union, which restrict the storage and processing of personal data (GDPR) and the storage of other data (ePD) with regard to data subjects.

Much of this guide revolves around how to set this up in Google Tag Manager, but the overview of the feature applies to implementation using the Global Site Tag (gtag.js) as well.

Disclaimer: This article is a technical overview of how consent mode works. You need to align the implementation with whatever laws and regulations apply to your organization and the users that visit your site(s).

Make sure you read the official support documentation as well as the developer guide to get up to speed.

First of all, consent mode is not a consent management platform. For consent mode to be effective, you need to already have a system or solution in place for collecting and resolving the user’s consent with regard to the data being collected on your site.

Consent mode has two variants. There are the default settings the page will use while waiting for the user’s consent status to be resolved. Then there are the updated settings that are sent as soon as consent has been resolved.

Default settings should be established as early as possible in the page load. Ideally, you’d add a new gtag snippet to the top of the page template, and establish the default consent settings in that snippet.

Note! You do not have to be using gtag.js to deploy consent mode. The API just happens to be the global gtag() method, but it works fine with Google Tag Manager’s tags.

When Google’s tags fire, they will check the consent status from the default settings and act accordingly.

Once you’ve established the user’s consent, you can call the update command. This lets you change (or keep) the status of advertising storage and of analytics storage.

The gtag() call

As mentioned above, consent mode utilizes the gtag() API. The Google tags firing on the site will automatically read the consent status from this API when determining whether to read or write cookies and how to compile the network request to Google’s servers.

Here’s what the default snippet would look like. Remember, ideally this would be positioned at the top of the page. You can also fire it through Google Tag Manager using a Custom HTML tag or a custom template, but in that case you must make sure that it fires before any Google tags fire.

window.dataLayer = window.dataLayer || [];
function gtag() { window.dataLayer.push(arguments); }
gtag('consent', 'default', {
  ad_storage: 'denied',
  analytics_storage: 'denied',
  wait_for_update: 500,
  region: ['US-CA', 'FI']

The gtag() command above sets default consent settings for visitors from California (US-CA) and Finland (FI) to deny access to advertising and analytics storage. For these users, only cookieless pings will be sent to Google servers. There’s also a wait time of 500 milliseconds before any Google tags are allowed to fire, to give time for the update command to be invoked.

The region parameter is only relevant in the default command, as by the time you run update you should know whether to enable or disable storage for the current user regardless of where they are from.

Once you’ve established the user’s consent choices, you can execute the update command. In the following example, the user has given storage access for analytics tags but has denied access to storage for advertising scripts.

gtag('consent', 'update', {
  ad_storage: 'denied',
  analytics_storage: 'granted'

You don’t have to provide ad_storage again, as it was already denied in the default settings. However, I recommend to explicitly include them in the update command as well to make sure mistakes don’t lead to storage being used when the user hasn’t opted in to such a thing.

Restrict advertising storage

To restrict advertising storage, you need to call the default or update command and set the value of ad_storage to 'denied' in the consent object.

When advertising storage is restricted, here’s what happens:

  • No new advertising cookies are written. This means that if the URL has the gclid from a Google search ad click, for example, it will not be written in a first-party cookie.
  • No existing advertising cookies may be read. If there already was a cookie with a click identifier, this would not be used by or sent with the tags.
  • Third-party cookies are solely used for spam and fraud detection. If there already are cookies written on, for example,, they would be included in the request (assuming the browser doesn’t block third-party cookies), but Google says it will only use them for spam and fraud detection.
  • Google Analytics will not read or write advertising cookies, nor will it use them for Google Signals.
  • IP addresses are used solely for geolocation. They are not collected by Google Ads or Floodlight tags. Google Analytics does collect them, but you can opt in to IP anonymization.
  • The full page URL is collected with possible click identifiers. If the current page URL has click identifiers, they are sent to the advertising and analytics platforms with the current page URL.

Redact advertising data

You can increase the fidelity of advertising storage restrictions by additionally calling the following gtag() API:

gtag('set', 'ads_data_redaction', true);

This only works when you set ad_storage to denied.

When you do this, the following additional restrictions will apply:

  • Advertising hits will be routed through a new cookieless domain. Instead of routing them to or, the requests are sent to, which would not have any (advertising-related) cookies set on it by Google.
  • Ad click identifiers will be redacted from advertising requests and consent pings.
  • Page URLs with click identifiers will be redacted. Note that Google Analytics will still collect the full page URL with click identifiers in place.

Restrict analytics storage

If you choose to restrict analytics storage by setting the value of analytics_storage to denied in the consent object, Google Analytics will not be able to read or write first-party cookies.

This means that all hits that fire before the user reloads or navigates to another page will have the same client identifier (because it’s stored in a global variable). However, as soon as the user navigates away from the current page or reloads the page, a new client identifier will be sent with the hits on this new page load.

In other words, Google Analytics will not read or write the _ga cookie (even if one already exists). Instead, it will use an ephemeral identifier that exists solely for the duration of the current page load.

Importantly, restricting analytics STORAGE will not prevent hits to Google Analytics from being sent. The consent mode setting solely prevents Google Analytics from storing data in or reading data from browser cookies (or other storage).

However, these cookieless hits are sent to Google Analytics with a new gcs parameter, which includes the consent status of the hit. The cookieless hits are thus identified by Google Analytics and for now are not collected or exposed in reporting at all.

Most likely Google will at some point build actionable data out of the cookieless data set as well, perhaps after applying extensive modelling to make it align with the data that was collected with storage consent.

If you send the update command, you will be able to either deny or grant advertising and analytics storage access to all Google tags regardless of region.

If you deny storage access, then any tags that fire after the update call will be restricted as described in the previous chapters.

If you grant storage access, then tags will have full access to storage. If you grant access to advertising storage, then any ads data redactions you might have established will no longer apply.

In addition to this - as soon as you run the update command and grant access to advertising storage, all advertising pings that might have already fired without storage access will fire again. Thus cookies will be written and read, and the requests will be routed through domains that can carry third-party cookies as well.

URL passthrough

If you’re using gtag.js, you can toggle URL passthrough on. It checks the current page URL for advertising parameters (gclid, dclid, gclsrc, _gl), and adds them to all internal link URLs the user might be clicking through.

It’s a useful feature to have in case consent is granted outside the landing page, but it does lead to URL pollution and can mess up sites where functionality is based on a strict set of URL parameters (especially beyond obvious landing pages).

The command looks like this:

gtag('set', 'url_passthrough', true);

For this to work, the site must load a gtag.js library, so just using the gtag() API will not work.

If you’re using Google Tag Manager, you can achieve the same functionality by using the cross-domain linking capabilities of the Conversion Linker tag.

Google Tag Manager support

As you might have surmised, for now the Google Tag Manager support for consent mode is a bit flaky. Being forced to use the gtag() API is a bit backwards, considering we already have a global message queue named dataLayer at our disposal.

I’m absolutely positive that a more tightly-knit integration with GTM is on the way. I’m particularly hoping to see some or all of the following features:

  • Consent status exposed in dataLayer. Right now the gtag() consent commands are not available in dataLayer, making it impossible to check advertising and analytics storage status in case one wanted to apply them to other, non-Google tags as well.
  • Pre-load trigger. This is something I’ve been wanting to see for years. It would be so useful to have a trigger event for which all other Google Tag Manager events have to wait to complete before being initialized. It would be the perfect place for a consent mode tag, as all the other tags in the container would not be able to fire until the pre-load event has been completed.
  • First-class consent awareness. With this I mean it should be possible to have tags be consent-aware without having to build elaborate trigger setups. One of the most difficult things to set up when using GTM with a consent management platform is the conditional firing of tags depending on consent status.
  • Consent-aware APIs for templates. A logical extension of consent mode is that it should apply to non-Google tags as well. A perfect place for this would be in custom templates, where consent mode status could be applied to the APIs and network requests generated by custom templates as well.


First of all, remember that consent mode is a beta feature. It’s likely to change before it’s officially out of beta (at which point I’ll update this article accordingly).

In addition to a better Google Tag Manager integration, I’m also looking forward to more consent options, as limiting just “advertising storage” and “analytics storage” doesn’t really cut it when it comes to the granularity of how users should be able to decide how their data is collected and processed.

Nevertheless, consent mode gives you a nice way to control storage especially with advertising tags. You’ve already been able to control Google Analytics storage with the storage tracker setting, but now it’s also configurable via this gtag() API.

The main difference between consent mode and using the storage field to block analytics tags from having access to storage is that consent mode will not surface the data in reports whereas setting storage to none will.

It’s important to note that consent mode mostly applies to storage access and doesn’t actually block any requests. I’m certain there will be debate about whether this is enough or not. However, especially in the European Union the laws seem to be rather clear that as long as the nothing is stored (or read from storage), and as long as only ephemeral identifiers that can in no way be linked back to a natural person are used, this approach should be good enough.

You will need to trust Google on the ad_storage bit, though. Google promises they won’t use third-party cookies for other than spam and fraud detection, but this is difficult to audit.

Similarly, consent mode only covers the identifiers that we know about. There might be data leaks, intentional and unintentional, in requests to Google that allow far more data controlling options than the user has opted in to.

Still, I think any effort taken by Google to improve security and privacy control over their services is welcome. It’s just important that this doesn’t lead to complacency, though. Just because Google offers it natively doesn’t mean you can abandon due diligence in making sure that consent (and any other legitimate purposes) are observed and periodically audited.