← Guides·Data Privacy

Data Privacy

Consent-aware server-side tracking: sGTM and Meta CAPI

Where the consent decision is enforced once tracking moves to server-side GTM and Meta CAPI, how gcs and gcd travel with the event, and how to check it.

David PombarSwiss army knife at Trackingplan
8 min read · 1846 words

TL;DR Moving to server-side GTM and Meta CAPI does not move the consent decision: your banner still collects it in the browser. What changes is that the decision has to travel with every event, and that each tag in the server container has to read it. Google’s tags do that for you. Every other destination forwards whatever it receives until you add the check. This guide shows where to enforce it and how to test it, as part of privacy compliance for analytics.

Consent-aware server-side tracking means that a server container, or your own backend, sends an event to a vendor only when the visitor’s consent allows it, and sends it in the form that consent allows. It sounds like the default. It is not. A server container is a router: it forwards what it is told to forward, and it has no banner of its own.

The browser stops being the last place where a decision is made. In a client-side setup, the consent banner, the tag manager, and the vendor’s script all live on the page. If a tag is blocked, its request never leaves the browser, and you can see that in the network tab.

In a server-side setup, the page sends one request to your own collection endpoint, usually a subdomain such as metrics.example.com. The server container receives it and fans it out: GA4, Google Ads, Meta, TikTok, and whatever else has a tag there. The vendors’ requests leave from your server, not from the visitor’s browser, so the network tab no longer shows them.

Two flows side by side. Client-side: the consent banner gates each vendor tag in the browser. Server-side: the browser sends one request with the consent state to a server container, which forwards it to GA4, Google Ads, Meta CAPI, and TikTok.
Client-side, the banner gates each tag on the page. Server-side, it can only gate the one request to your container; the fan-out happens out of sight.

Three things follow:

None of this changes what the visitor agreed to. Server-side tagging changes where requests are sent from, not the legal basis for sending them.

With Google Consent Mode, the state rides on the request itself. Google’s consent mode overview describes the two parameters that carry it: gcs transmits ad_storage and analytics_storage, and gcd encodes the detailed state of each consent type, including ad_user_data and ad_personalization. Your CMP updates the Google tag; the Google tag adds those parameters to every request it sends, including the one to your server container.

An annotated request from the browser to a server container at metrics.example.com, with the gcs parameter marked as ad_storage and analytics_storage, and the gcd parameter marked as the four consent types.
The consent state is part of the request the server container receives. Values are illustrative.

Google’s guide to consent mode in server-side tagging is short on purpose: you set up consent mode in the web container only, the GA4 client in the server container receives the consent parameters, and “Google product tags in the server are consent-aware”. A denied state changes their behavior: GA4 sends measurements without cookies, Google Ads conversions stop reading and writing cookies, and remarketing and Floodlight requests are blocked. If you want to read how gcs and gcd look in a real request, our guide to debugging Google Consent Mode v2 decodes both.

Two conditions have to hold for this to work. The request that reaches the container has to carry the parameters, which means your web setup sets a default before the Google tag sends anything. And the client that receives the request has to be one that parses them. A custom client, a webhook from your backend, or a data tag built by a third party may not.

Where non-Google destinations fall through

Google’s documentation covers Google’s tags, and only those. A Meta Conversions API tag, a TikTok Events API tag, or an HTTP request tag you built yourself does not read Consent Mode unless someone made it read it. In the server container, a tag fires when its trigger matches. If the trigger is “every purchase event”, the purchase goes to Meta whatever the visitor chose.

One incoming purchase event with ad_storage denied fans out to four tags. GA4 and Google Ads adjust to the denied state; the Meta CAPI and TikTok tags forward the event unchanged because nothing checks consent.
Same event, same denied state: Google’s tags adjust, the others forward unless a condition stops them.

This is a common gap after a migration. The browser pixel was blocked by the CMP, so the team assumes Meta receives nothing for visitors who rejected. Then the CAPI tag in the server container sends the conversion anyway, often with hashed email and phone attached for matching. The browser side looks compliant. The server side is not.

The fix is to give every non-Google tag a consent condition:

Where to enforce the CMP decision

There are three places a decision can be enforced, and a server-side setup usually needs all three.

Three enforcement points along the data path: in the browser, the CMP and the default stop or shape the request; in the server container, a consent condition per tag; in the backend, the consent stored with the order before an offline or CAPI event is sent.
One decision, three places to enforce it. Each one covers events the others never see.
WhereWhat it controlsWhat it misses
Browser (CMP, Consent Mode default and update)Whether the request to your container is sent, and which consent state it carriesEvents your backend sends on its own
Server container (trigger conditions, transformations)Which vendors receive each event, and which fields they getRequests that arrive without a consent state
Backend (order system, CRM, webhooks)Server-to-server events such as confirmed purchases, refunds, or leadsNothing, if the consent was stored with the record

The backend is the one teams forget. A purchase confirmed by your order system, a qualified lead pushed from your CRM, or a subscription renewal sent through CAPI never passed through a banner at that moment. The only consent it can respect is the one you stored when the visitor gave it. If the order does not carry the consent state from checkout, the event has nothing to check against.

What Meta CAPI asks for, and what it does not

Meta’s server event parameters are worth reading with consent in mind:

How to check it, step by step

Test the setup the way a visitor uses it: three consent states, the same journey, and every destination checked.

A test matrix with three consent states as columns (banner unanswered, rejected, accepted) and four destinations as rows (GA4, Google Ads, Meta CAPI, TikTok), showing the expected result in each cell.
Write the expected result in every cell before you test. An illustrative matrix; your DPO decides the expectations.
  1. Write the matrix first. For each destination and each consent state, write what should happen: not sent, sent without identifiers, or sent in full.
  2. Check the request to your container. In the browser’s network tab, find the request to your collection endpoint and confirm that it carries gcs and gcd, and that their values change when you answer the banner.
  3. Open the server container’s Preview. For each incoming event, check which tags fired, which did not, and what each outgoing request contained. Preview also shows which transformations ran for a tag and the event data before and after them.
  4. Check the destinations. Meta’s Test Events in Events Manager shows the server events it received; compare them with the matrix.
  5. Repeat for your backend events. Send a test order with each stored consent state and check what your integration sends.
  6. Repeat after every container publish. A new tag added with a broad trigger reopens the gap.

A test covers the journeys you ran, on the day you ran them. Real traffic has the market with a different default, the client that skips a parameter, and the tag someone published last Friday.

Trackingplan reads the consent state traveling with every hit and checks every vendor against it, across web, mobile, and server-side. Since October 30, 2026, when a server-side GTM container forwards a conversion to Meta, TikTok, Bing, Snapchat, Pinterest, Adform, LinkedIn, or Roivenue, Trackingplan reads the Google Consent Mode state the container copied from the browser event. Those destinations appear on the Consent screen next to your Google ones, and on a hit the source reads Google Consent Mode (Server Side GTM).

It observes and reports; it does not block tags. When a server-side destination receives events it should not, the finding names the destination and the hits behind it, so the fix is a trigger condition, not an investigation. Server containers connect through the server-side GTM installation.

Consent-aware server-side tracking is not a setting you switch on. It is a check you add to every tag that leaves your container, and one you keep checking after every publish.

Frequently asked questions

No. Server-side tagging changes where requests are sent from, not what the visitor agreed to. The visitor’s choice is still collected in the browser by your consent banner, and it has to travel with every event to the server container, where each tag must respect it.

Google’s own tags do. Google’s documentation says Google product tags in a server container are consent-aware: they read the consent parameters the Google tag adds to the request and adjust their behavior. Other tags, such as a Meta Conversions API tag, need a condition you configure yourself.

Can I send Meta CAPI events for visitors who rejected cookies?

Only if your legal basis allows it, which is a question for your DPO, not for the tag. Technically nothing stops a server container or a backend from sending the event, which is exactly why the consent check has to be built in. Meta’s Limited Data Use option is a processing restriction for some US states, not a record of consent.

Run the same journey three times: banner unanswered, rejected, and accepted. In each run, check that the request to the server container carries the gcs and gcd values you expect, then use the server container’s Preview to see which tags fired and what they sent. Compare the result with what each destination received.

David PombarSwiss army knife at Trackingplan

Read more from David, a Senior Product Strategist with 18+ years in digital product development and an atypical error detection knack.

Trackingplan

See everything. Miss nothing.

Your implementations audited around the clock with real-time, real-user data. Real-time alerts about errors or changes in your data, campaigns, pixels, privacy and consent. Let AI flag issues before they cost you.