Back to the blog

Blog

A cookie banner in front of server-side tagging: what changes, and what does not

Published · 4 min read

The question arrives in two forms. "Do I still need a banner if the tags are first-party now?" — yes. "Does my banner still work if the tags are first-party now?" — usually, but the way it can fail is silent, and it is worth twenty minutes to make sure. This is not legal advice; it is a description of the mechanics, so that whatever your counsel tells you to do, the setup actually does it.

What server-side tagging changes about consent: nothing

A first-party hostname is a technical property of a request. It is not permission. If you needed consent to set an analytics cookie yesterday, you need it today, and the fact that the cookie is now set by metrics.yoursite.com instead of google-analytics.com does not enter into it. The regulator's question is what you collect and why, not which server the packet visited on the way.

What does change is where a blocked request goes. Ad blockers and browser privacy features block by hostname and by URL pattern, and they block googletagmanager.com. They do not block your own domain. So a visitor who has consented and would have been silently dropped by a filter list is now counted. That is the whole benefit, and it is only a benefit for visitors who consented.

Consent Mode, in one paragraph

Google's tags read a consent state with a handful of named permissions — analytics_storage, ad_storage, ad_user_data, ad_personalization — and adjust what they send. Before the visitor decides, a consent manager pushes a default of denied; when they choose, it pushes an update. In the denied state the Google tag still fires, but sends a cookieless ping: no client ID, no cookie, a signal that a page was seen and no more. Once analytics_storage is granted, it sends the full hit. The server container receives whichever was sent, and the consent signals travel with the hit, so the server-side GA4 tag behaves the same way.

Order matters, and SignalHost's tags do not add conditions of their own

The consent manager has to load before the Google tag, so that its default is in place when the tag first evaluates. Most consent managers provide a wait_for_update value for exactly this — a few hundred milliseconds the tag holds for a consent state before assuming denied.

The entities SignalHost creates in your container carry no consent conditions. That is deliberate. Google's own tags honour Consent Mode; a hand-added consent check on the Google tag, with none on the GA4 event tags beneath it, is the first of the two mistakes below.

Mistake one: gating the Google tag and not the event tags

The Google tag is what routes measurement through the server container. A GA4 event tag — a purchase tag, say — can send on its own. If the Google tag waits for consent and the event tags do not, the event tags fire before consent and send straight to Google, and they send from a page whose banner is still open. The container page shows nothing wrong, because the hits never came through the container.

Either gate nothing by hand and let Consent Mode do it, or gate every tag that can send. There is no consistent middle.

Mistake two: a blocking consent manager that does not recognise your own loader

Some consent managers work by blocking scripts until consent is given — they intercept script tags by URL and hold them. Their lists know googletagmanager.com. They do not know exxz2gdaz1jz.yoursite.com, because nobody's list could: the loader's hostname and filename are unique to your container. So in blocking mode the loader may be let through unconditionally, and if you are relying on blocking rather than on Consent Mode, that is a tag firing before consent.

Two ways through. Add the loader's URL to the consent manager's block rules by hand, in whatever category your analytics belongs to. Or — better, because it also handles the cookieless ping correctly — rely on Consent Mode for Google's tags and use blocking only for scripts that do not support it. Our own site runs a consent manager in auto-blocking mode with Consent Mode alongside; the Google tag is placed after the consent manager's script, and a test in the repository fails if anyone reorders them.

The server side, and the other destinations

The consent state arrives at the server container inside each hit, and the server-side GA4 tag reads it as the browser-side one would. Nothing on our side grants or upgrades consent; a cookieless ping stays a cookieless ping.

If you connect a Meta or TikTok destination, the same hits feed those. Whether a visitor's denied marketing consent should stop those forwards is a decision your consent manager expresses — through which category the loader sits in, and whether Consent Mode's ad_storage is respected by your setup. Check it the way you would check anything here: open the site with the banner unanswered, watch the network tab, and see what leaves.

A checklist

  • The consent manager's script is above the Google tag in the page.
  • A default consent state of denied is pushed before the tag loads, with a wait_for_update.
  • No tag in the container has a hand-added consent condition — or every tag that can send has one.
  • With the banner unanswered, the network tab shows a cookieless ping (gcs=G100 in the request) and no full hit.
  • After accepting, the same page shows a full hit and the container page counts it.
  • If the consent manager blocks by URL, the loader's URL is in its rules.

Stop losing data to ad blockers

Ten thousand requests a month, free, for as long as you like. Four minutes to find out whether it helps.