Server-Side GTM
The problem client-side tagging can no longer solve
Standard (client-side) GTM runs entirely in the visitor's browser: every tag — GA4, Meta Pixel, ad platform conversion tags — fires as JavaScript loaded directly from Google's and each vendor's own domains. This made tag management simple for a decade, but two things broke it: browser vendors (Safari's ITP, Firefox's ETP) increasingly block or truncate third-party cookies and scripts by domain, and ad blockers filter requests to known tracking domains like googletagmanager.com and facebook.com by name.
Server-side GTM (sGTM) moves tag execution off the browser and onto a server you control. Instead of the browser talking directly to Google and Meta, it talks to a single first-party endpoint on your own domain, which then forwards data server-to-server to each destination. The browser sees one first-party request; ad blockers and ITP have nothing recognizable to block.
The architecture: two containers, not one
A server-side setup always involves two separate GTM containers working together:
1. Web container (the familiar client-side GTM) — still runs in the browser, but instead of sending data directly to GA4 or Meta, it sends events to your server container's URL.
2. Server container — runs as a tagging server (typically on Google Cloud Run, though any container-hosting environment works) and receives those events, then fires server-side tags (a GA4 server tag, a Meta CAPI tag) that forward the data to each destination's server API.
The server container isn't magic — it's a real, billable piece of infrastructure you deploy and maintain. This is the single biggest mental shift from client-side GTM: you now own a small server application, with real infrastructure decisions (region, scaling, cost) attached to it.
First-party by domain, not just by cookie
metrics.yoursite.com — instead of using Google's default *.appspot.com URL. A request to your own subdomain is, from the browser's and ad blocker's perspective, indistinguishable from any other first-party API call your site makes. Skip the custom domain and you've deployed a server container that's still trivially identifiable and blockable.The request path, end to end
Tracing one pageview through a properly configured sGTM setup:
1. Browser loads the page; web container GTM fires as usual.
2. Instead of the GA4 tag sending directly to google-analytics.com, it sends to your server container's endpoint at metrics.yoursite.com/g/collect (the same request path GA4 normally uses, just proxied through your domain).
3. Your server container (a Node.js app built on GTM's server runtime) receives the request, runs its own trigger/tag logic — the same trigger-fires-tag model as client-side GTM, just server-side.
4. The server-side GA4 tag forwards the event to Google's Measurement Protocol endpoint; a server-side Meta CAPI tag simultaneously forwards a matching event to Meta's Conversions API — all from the server, none of it visible to browser-based blocking.
Browser (yoursite.com)
|
| POST https://metrics.yoursite.com/g/collect <- first-party, custom domain
v
Server Container (Cloud Run, mapped to metrics.yoursite.com)
|
|--> GA4 server tag --> Measurement Protocol API (Google)
|--> Meta CAPI tag --> Conversions API (Meta)
|--> [any other server-side destination tag]Deduplication: the trap almost every migration hits first
The most common server-side rollout mistake is sending the *same* conversion event twice — once from a client-side pixel that's still active, and once from the new server-side tag — resulting in doubled conversions and inflated ad platform reporting. Meta CAPI and the Meta Pixel deduplicate automatically if you attach the same event_id to both the browser-side Pixel call and the server-side CAPI call for the same user action; Google Ads deduplicates similarly via a shared transaction or click identifier.
The rollout discipline: before removing any existing client-side pixel, first run the server-side tag in parallel with a matching event_id, verify in each platform's event-testing tool that events are being deduplicated (not double-counted), and only then decommission the redundant client-side tag.
Never launch both pixels without a dedup key
Custom domain setup and load balancer routing
Pointing a subdomain at a Cloud Run server container isn't a simple DNS CNAME in most production setups — Google recommends fronting the container with a Global External Load Balancer, which gives you a stable IP, supports the SSL certificate for your custom domain, and can cache static server-container assets at the edge. The load balancer is also where you'd add basic bot filtering or rate limiting in front of the tagging endpoint, since it's now a public API surface exposed to the internet, not just an internal script tag.
Client identification without third-party cookies
Server-side tagging alone doesn't solve identity — you still need a way to recognize the same visitor across requests. The standard approach is a first-party cookie set by the server container itself (GTM's server-side GA4 client handles this automatically, setting a _ga cookie scoped to your own domain rather than Google's). Because the cookie is set by your first-party server, not a third-party script, it survives ITP's cookie lifetime restrictions that would otherwise cap third-party cookies at 24 hours or less.
When server-side tagging is (and isn't) worth the cost
sGTM adds real infrastructure cost and maintenance — a Cloud Run bill that scales with traffic, a load balancer, SSL certificate management, and a team member who understands server-side trigger/tag logic well enough to debug it. It's clearly worth it for businesses with meaningful paid media spend where ad-blocker and ITP data loss directly costs money in misattributed conversions — ecommerce and lead-gen businesses running Meta and Google ads at scale are the canonical case. For a low-traffic site with no paid acquisition, the operational overhead usually isn't justified by the marginal data-quality gain.
What's next
Server-side tagging is the delivery mechanism; what actually gets delivered still depends on the event schema and consent state decided upstream. Consent Mode governs what data server-side tags are even allowed to send once a visitor has made a privacy choice.
Next: Consent Mode v2 →
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.