Consent Handling in Server-Side GTM
Server-side GTM does not run in the user’s browser — it runs on your server infrastructure. This changes the consent architecture significantly. The browser still handles the CMP, the banner, and the user’s consent choice. But the consent signal needs to travel from the browser to your sGTM container, where it determines which vendor tags fire.
This architecture gives you something powerful: a central enforcement point for all outbound data requests, regardless of what client-side code does.
How consent signals reach sGTM
Section titled “How consent signals reach sGTM”The consent state from the browser’s Consent Mode does not automatically propagate to sGTM. You need to explicitly forward it.
Via the GA4 client
Section titled “Via the GA4 client”The most common setup: the browser sends events to sGTM via the GA4 client. When events arrive, the GA4 client parses the gcs parameter from the hit URL — the consent signal that GA4 automatically appends to every request.
The gcs parameter encodes the current consent state:
G111= bothad_storageandanalytics_storagegrantedG100= both deniedG101= onlyanalytics_storagegrantedG110= onlyad_storagegranted
The sGTM GA4 client makes this available in the event model. You can read it in server-side variables and use it to condition tag firing.
// sGTM Custom Variable — reads consent state from incoming GA4 hit// Variable type: Custom JavaScript
const eventModel = require('getAllEventData');
function getConsentState() { const consentParam = eventModel()['x-ga-gcs']; // x-ga-gcs is how the consent signal appears in sGTM's event model return consentParam || 'unknown';}
return getConsentState();Via explicit consent parameters
Section titled “Via explicit consent parameters”A more reliable approach: explicitly include consent state as an event parameter in your dataLayer pushes. This travels through sGTM as a regular event parameter and is accessible via any variable type.
// Browser dataLayer push — include consent state explicitlywindow.dataLayer.push({ 'event': 'page_view', 'consent_analytics': analyticsGranted ? 'granted' : 'denied', 'consent_advertising': advertisingGranted ? 'granted' : 'denied'});In sGTM, read these with Event Data variables pointing to consent_analytics and consent_advertising.
Reading consent state in sGTM variables
Section titled “Reading consent state in sGTM variables”Create reusable variables for consent state checks:
Variable: Consent - Analytics Storage
// Custom JavaScript variable in sGTMconst getAllEventData = require('getAllEventData');
function() { const eventData = getAllEventData();
// Check explicit consent parameter first if (eventData.consent_analytics) { return eventData.consent_analytics; }
// Fall back to decoding the gcs parameter const gcs = eventData['x-ga-gcs'] || ''; // gcs format: G{ad_storage}{analytics_storage} // Third character is analytics_storage: 1=granted, 0=denied if (gcs.length >= 4) { return gcs[3] === '1' ? 'granted' : 'denied'; }
return 'unknown';}Variable: Consent - Ad Storage
const getAllEventData = require('getAllEventData');
function() { const eventData = getAllEventData();
if (eventData.consent_advertising) { return eventData.consent_advertising; }
const gcs = eventData['x-ga-gcs'] || ''; if (gcs.length >= 3) { return gcs[2] === '1' ? 'granted' : 'denied'; }
return 'unknown';}Conditional tag firing based on consent
Section titled “Conditional tag firing based on consent”With consent variables in place, use them in tag firing conditions.
Approach 1: Trigger conditions
In sGTM triggers, add a condition:
- Variable:
{{Consent - Analytics Storage}} - Condition: equals
granted
Any tag on this trigger only fires when analytics storage is granted.
Approach 2: Tag configuration
Inside a Custom Tag template, check consent state before executing:
// Inside a server-side tag templateconst getAllEventData = require('getAllEventData');const logToConsole = require('logToConsole');const sendHttpRequest = require('sendHttpRequest');
const eventData = getAllEventData();const analyticsConsent = eventData['consent_analytics'];const adConsent = eventData['consent_advertising'];
// Gate: only send to advertising vendor if consent grantedif (adConsent !== 'granted') { logToConsole('Advertising consent not granted. Skipping vendor tag.'); data.gtmOnSuccess(); return;}
// Proceed with vendor tag executionconst pixelUrl = buildPixelUrl(eventData);sendHttpRequest(pixelUrl, function(statusCode) { if (statusCode >= 200 && statusCode < 300) { data.gtmOnSuccess(); } else { data.gtmOnFailure(); }}, {method: 'GET', timeout: 3000});PII redaction based on consent
Section titled “PII redaction based on consent”sGTM is the ideal place to strip PII from events before they reach third-party vendors. When consent for certain processing is denied, you can redact personal data fields before forwarding:
// sGTM Custom Tag — PII redaction layerconst getAllEventData = require('getAllEventData');const setEventData = require('setEventData');const logToConsole = require('logToConsole');
const eventData = getAllEventData();
// If advertising consent is denied, strip user identifiersif (eventData.consent_advertising !== 'granted') { // Remove email address setEventData('user_data.email', null); setEventData('user_data.email_address', null); setEventData('user_data.sha256_email_address', null);
// Remove phone setEventData('user_data.phone_number', null); setEventData('user_data.sha256_phone_number', null);
// Remove address data setEventData('user_data.address', null);
logToConsole('PII redacted: advertising consent not granted');}
data.gtmOnSuccess();Run this as a Setup Tag before any tags that might forward user data. This approach centralizes PII handling — you do not need to configure redaction in every individual vendor tag.
The compliance advantage of sGTM
Section titled “The compliance advantage of sGTM”Client-side consent relies on each vendor’s JavaScript tag respecting the consent signal. If a vendor tag has a bug, is updated unexpectedly, or does not natively support Consent Mode, consent can be violated without you knowing.
sGTM reverses this dynamic. Your server-side container is the last point before data leaves your infrastructure and reaches vendor APIs. You control:
- Which events reach which vendors
- What data is included in each request
- When to drop a request entirely based on consent
This centralization is the primary compliance advantage of server-side tagging beyond the performance and first-party data benefits.
Client-Side Consent Enforcement
Each vendor tag must respect Consent Mode signals independently.
A single misbehaving or outdated tag can violate consent.
Consent enforcement is distributed — no single control point.
Tag behavior depends on vendor implementation quality.
Server-Side Consent Enforcement
sGTM is a central gatekeeping layer before all vendor API calls.
You control what data leaves your server regardless of vendor behavior.
Single place to audit and enforce consent compliance.
PII redaction and consent gating apply to all downstream tags simultaneously.
Consent state and the sGTM event model
Section titled “Consent state and the sGTM event model”When an event arrives at sGTM, the event model contains all event data including consent signals. Check available fields in the sGTM debugger (Preview mode):
Key fields to look for:
x-ga-gcs— the Google consent signal from GA4 hitsx-ga-rdp— restricted data processing flag- Any custom consent parameters you pass explicitly
In Preview mode, click any incoming request and check the Event Data panel to see the full event model. Consent-related fields will appear alongside your regular event parameters.
Common mistakes
Section titled “Common mistakes”Assuming sGTM automatically knows about browser consent. sGTM receives no automatic consent signal unless you explicitly forward it from the browser. The consent state must travel as data in your events.
Only gating tags with trigger conditions but not redacting PII. A tag that fires with denied consent but strips PII is still firing when it shouldn’t. Use both gating (don’t fire) and redaction (strip data if you must fire for other reasons).
Not testing the full consent-denied path through sGTM. Browser testing shows the browser side. You must also verify in sGTM Preview mode that denied-consent events do not reach vendor tags. Check sGTM’s Preview mode independently from GTM’s browser Preview.
Relying on x-ga-gcs without validating it. The gcs parameter can be absent or malformed. Always have a fallback value and treat unknown as the most restrictive state.