Configure Consent Mode v2 in your web GTM container so the state is set before any tag fires. Google then attaches it to the request it sends onward, as the gcs parameter, so nothing needs sending twice. In the server container, read that state, gate each vendor tag on it, and check your GA4 client is not quietly restoring an identifier.
The signal does not take a separate route
The usual way this gets built wrong is to treat consent as something the server container must be told about independently, through a second integration. The state the visitor chose is attached to the same request that carries the event, so if the web side is right the server side already has it.
That has a consequence worth stating plainly, because it decides where you go when something breaks: a server container cannot repair a consent problem. It has no banner and no visitor to ask. If the state never left the browser correctly, every gate you build there is checking an empty field. The duty side of this is in do you still need a cookie banner with server side tagging.
How to pass the consent signal to a server side tagging container
Set Consent Mode v2 in the web container, not the server one
Consent is decided in the browser and configured in your web GTM container: the CMP sets a denied default for every non essential signal before any tag initialises, then updates it when the visitor chooses. The server container has no banner and no visitor to ask, so it is never the place to fix a consent problem.
Confirm the state is actually on the outgoing request
In a private window, find the request your Google tags send to the server container. It should already carry a gcs parameter: G100 for both storage types denied, G111 for both granted, G101 and G110 mixed. G1-- means the tag fired with no consent state attached and everything downstream is guessing.
Read the consent state inside the server container
Open the server container preview and inspect an incoming event. The state arrives with the request and is readable there, which is what lets a tag decide whether to fire. Give yourself named variables for the signals you gate on, rather than raw fields at each tag.
Gate every vendor tag on the signal it actually needs
Each tag gets a firing condition tied to the right category, and the categories are not interchangeable. Analytics tags check the analytics signal. Advertising destinations, a conversions API among them, check the advertising signals, and version 2 added two that older setups never gate on. A tag with no condition fires on everything, denials included.
Check what your GA4 client does with cookies
The step no guide includes, and the one that quietly undoes the other four. The GA4 client has a cookie setting. Left on the server managed option it mints and restores a first party identifier of its own, so it can attach a persistent id to a ping that was supposed to be anonymous. Set it to javascript managed so the client uses the identifier the browser sent, and nothing more.
Verify with a denial, not with an acceptance
Everybody tests by accepting, because that is the path where data appears. Reject instead, in a clean private window, then follow that one event through: the state on the request, the state inside the container, which tags fired, and what identifier left for each vendor.
The failure that survives a correct setup
Steps one to four are what every guide covers, and a setup that passes them looks finished. Step five is the one we keep finding in carefully built containers, and it does not look like a consent bug at all.
The shape of it: the banner is right, the default is denied, the state reaches the container intact, and the vendor tags are gated correctly so a denied event fires no advertising tag. Everything you would test passes. Meanwhile the GA4 client is managing its own cookies, so on each request it mints or restores a first party identifier and writes it onto the event. A ping that was supposed to leave anonymous goes out carrying a stable id.
The symptom never points at consent. It reads as counts slightly too high, and sessions that should have been unattributed arriving attributed. We traced exactly this in a live server container debug session, and the fix was one setting. Nothing about the gating changed, because the gating had never been wrong.
The lesson generalises. Gating the tags and controlling the identifier are two different jobs. A gate decides whether a request reaches a vendor. An identifier decides whether that vendor can tell who it was about. The documentation covers the first and is silent on the second, so a container can follow the guidance exactly and still hand out identity.
What the wiring is worth when it holds
Across Amplio Data client implementations the measured baseline is around 34% of sessions sitting behind the banner, with 20 to 40% of the lost conversions recoverable once consent is set the way Google expects and the identifier is handled honestly. Figures are measured ranges across Amplio Data client implementations, not a guarantee. Recovery depends on your traffic mix, regions and how your tags are configured.
That recovery comes from modelling and from correctly attributed permitted traffic, never from quietly re identifying people who declined. A container that leaks an identifier is not recovering data, it is collecting data it was refused, and the fact that it flatters the dashboard is what hides it.
The short version
Consent is decided in the browser and configured in the web container. It reaches the server on the request itself, in gcs, with no second integration. Read it there, gate each vendor tag on the category it needs, and set the GA4 client to use the identifier the browser sent rather than minting one. Then prove it on a rejected event. The browser side procedure is in how to check your banner is sending the signal, and which mode you are running is in basic versus advanced Consent Mode.
Velo sets all four signals from one snippet before your tags initialise, which is the upstream half of the above. The mechanism is on the product page.
Common questions
How do you pass the consent signal to a server side tagging container?
You do not pass it separately. Configure Consent Mode v2 in your web container so the state is set before any tag fires, and the Google tag attaches it to the request it sends onward, where it arrives as the gcs parameter. Server side, read it, gate each vendor tag on the category it needs, and verify on a rejection that the right tags stayed silent.
Do you configure Consent Mode in the server container or the web container?
The web container. The banner, the denied default and the update all live in the browser, and the server container has no visitor to ask. It only acts on a state decided upstream, which is why it cannot repair a consent problem: if the state never left the browser correctly, there is nothing there for a tag to check.
Does server side tagging mean you no longer need a cookie banner?
No. Moving the request to your own domain changes where the data goes, not whether you were allowed to collect it. Consent is permission to process, and that is unaffected by which server receives the hit. Server side tagging makes a correct consent setup more valuable, but it removes none of the duty to ask.
Why is data still reaching GA4 when consent was denied?
Usually the identifier rather than the gate. If the GA4 client in your server container manages cookies itself, it can mint or restore a first party id and attach it to a ping meant to be anonymous, so hits that should look consentless arrive looking like a known user. Point the client at the identifier the browser sent instead. The other cause is a vendor tag with no firing condition at all.
How do you verify the consent signal reached the server container?
Follow one rejected event end to end: the gcs value on the outgoing request, the consent state on the incoming event in the server container preview, which tags fired against it, and what identifier each outgoing request carried. Testing only the acceptance path is the usual mistake.