20 October 2026 · 8 min read

Consent Mode in Server-Side GTM: What the Container Does Not Do

Every few months a team moves its tags into a server container and closes the consent ticket. The reasoning sounds solid. Data now leaves through a domain we control, the browser sees fewer third-party calls, so the awkward part is handled.

It is not. A server container is a relay. It receives a request, reads what that request says about consent, and fires the tags you configured. Google's own tags react to the state they are given. Several of the other things sitting in the container do not, and three of the settings people expect it to enforce never reach the server at all.

What actually arrives at the container

Google documents the flow in three steps. The consent banner on the site takes the visitor's choices and passes them to the Google tag. The Google tag sends those preferences to the server container by adding consent parameters to the HTTP request. Google's product tags in the server are consent-aware and adjust how much data they send.

Three pieces have to exist for that to work: a web container, a server container, and a Google Analytics GA4 client inside the server container to receive the consent data. Remove the client and the request still lands, but nothing interprets the consent state carried in it.

Read the third step carefully. The guarantee is scoped to Google product tags. That scope is where most of the surprises live.

Built-in consent checks cover four tags

The tags with built-in checks are Google Analytics, Google Ads, Floodlight and the Conversion Linker. The Google Ads entry covers both conversion tracking and remarketing.

Everything else needs a check you supply. Tag Manager gives you the mechanism. In a tag's Advanced settings, under Consent Settings, Additional Consent Checks can be set to require consent for named types, and the tag then fires only when every listed type reads granted. Google documents that control for web tags and adds a line worth keeping: third-party consent platforms may ship different default built-in behaviour of their own.

In a server container the practical version is blunter. A Custom HTML template, a social pixel, an affiliate postback: each one receives the event data and the consent parameters attached to it, and then does whatever its author wrote. If the author never read the consent field, the tag fires. Nothing in the platform intervenes.

So the first job on any server container is bookkeeping. Open the tag list and mark each tag as either has a built-in check or has mine. Anything left unmarked is a tag whose behaviour under denial you cannot describe, and that includes tags added six months ago by someone who has since left.

Basic and advanced mode are decided upstream

Basic mode blocks Google tags until consent arrives. Advanced mode loads them either way and sends cookieless pings when consent is refused.

Advanced is the mode Google wants. Its guidance says plainly that blocking tags until consent means you will not get the full benefits, and the comparison table shows the bill. Behavioral modelling in Analytics does not happen under basic mode, and Ads conversion modelling falls back to a general model built from browser type, event type, time of day and similar high-level signals rather than anything observed on your site.

In a server setup that choice was made upstream. If the web container blocks the Google tag, the request never reaches the server container, so the server configuration never gets a vote. Teams that migrate to server-side and leave the client-side block untouched have added infrastructure around a decision taken somewhere else, and they usually find out when the modelled conversions do not appear.

Four Google tags, four denial behaviours

Knowing what each tag does under denial is the difference between a configuration you can defend and one you hope nobody tests.

The Conversion Linker detail catches people. A team adds it to the web container, assumes the server inherits it, and then wonders why conversions stop landing for everyone who declined.

Three settings that never cross the boundary

This is the part worth printing. Three controls that get enabled inside a server container, where they do nothing at all.

Redaction deserves its own paragraph, because it is widely misunderstood. With ad_storage denied and ads_data_redaction set, ad click identifiers are redacted from the consent and key event pings sent to Google Ads. Google Analytics still collects the full page URL, and that URL can contain a GCLID. Redaction narrows what advertising systems receive. It does not scrub the page location your Analytics property records, and it is not a substitute for stripping parameters at the source.

The TCF point carries a second consequence that rarely gets mentioned in migration plans. When visitors deny consent through a TCF-based consent platform, Analytics cannot model the missing data. A TCF banner in front of a server container is a modelling dead end, and no amount of server configuration changes it, because the decision lives with the consent platform and the web container.

The cookieless ping is not an empty request

Denied does not mean blank. Cookieless pings can carry a timestamp, the user agent, the referrer, screen resolution, the IP address (used to derive country, and not logged by Analytics), whether the current or a previous page in the session held ad click information, a boolean consent state, a random number generated per page load, and the developer ID of the consent platform in use.

One sentence in Google's documentation matters more than the rest for anyone running server-side: if the advertiser sets other fields such as user_id and custom dimensions, they will be sent normally. A server container is exactly where teams enrich events with a CRM identifier, a hashed email or an internal account number, because that enrichment is the reason they moved. Denial does not strip those fields. If a value cannot leave the building without consent, it should not be attached before consent, and the container will attach it if the logic tells it to.

Region-specific defaults break where the visitor becomes unknown

Advanced mode plus region-specific defaults is the setup most European teams want: grant by default, deny for the regions that require it. That needs the server to know where the visitor is, and out of the box it does not.

Google's guidance is to send the region in request headers from the tagging server. Which header depends on what you run on:

After that the container needs a Visitor Region variable, either the built-in one that reads those headers or a custom variable assembled from two request header variables. Then the client receiving the web requests needs region-specific settings enabled, with that variable mapped into the Region field.

Verification is quick and unforgiving. Open Preview, load the site through your first-party path, select the claimed client, switch Display Variables to values and read the Region property. A country code means the headers arrived. The value undefined means they did not, which means every visitor is being treated as region-less and is almost certainly getting the more permissive default.

One cost note from Google's own page, since it decides the architecture: on GCP, custom request headers are billed per million requests, so the recommendation is to add geo headers only to script requests for gtm.js, /gtag/js and /gtag/destination rather than to all traffic. That is a routing rule in the load balancer, not a checkbox in Tag Manager.

What Tag Assistant will tell you, and what it will not

Tag Assistant checks four parameters: ad_storage, ad_user_data, ad_personalization and analytics_storage. It shows them twice, as the on-page default and as the update after the visitor interacts with the banner.

Three failures it names directly. An empty Consent tab means consent mode is not implemented on the page at all. A default set too late means a tag already read or wrote a cookie, and the error is about ordering rather than values. A region that fails to adapt means the test needs repeating with a simulated location set in Chrome DevTools.

What it will not tell you is what your non-Google server tags did with the state they received. For that you open the container preview, select an event that arrived with denial, and check tag by tag, or you send a test event with every type denied and watch what leaves the server.

A week of work, in order

  1. List every tag in the server container and mark which ones have a built-in consent check.
  2. Confirm the Conversion Linker exists in the server container if Ads or Floodlight tags run there.
  3. Check that url_passthrough and ads_data_redaction are set in the web container, not the server.
  4. Confirm whether TCF is enabled in the web container for the entire page, and accept that denial under TCF removes modelling.
  5. Send the region headers, map the Visitor Region variable into the client, and confirm the Region property in Preview shows a country code.
  6. Send one test event with every consent type denied and record what each tag actually did.

None of that is dramatic work. It is the difference between a container that passes consent along honestly and one that is assumed to enforce it. The platform will do the first thing. It will not do the second, and it has never claimed otherwise.

Is Your Server Container Enforcing Consent?

North Digital audits server-side setups end to end: which tags check consent, what arrives at the container, and what leaves it. The output is a written record of what fires and what does not.

Talk to North Digital