Server-Side Tagging on a Gatsby or Next.js Site: Why and How
What server-side tagging actually is
Traditional Google Tag Manager runs in the user's browser. Every pixel (GA4, Meta, TikTok, LinkedIn) loads a script, fires from the client, and sends data directly to the vendor. Server-side tagging (SST) moves that work off the browser and onto a server you control. The browser sends one request to your own endpoint, and that endpoint fans out to the vendors on your behalf.
It sounds like a small architectural shift. The consequences are large.
Why it now matters
Four things have quietly made client-side tagging unreliable over the last few years.
Cookie lifetimes
Apple Safari's ITP caps third-party cookies at 7 days, and any first-party cookie set via client-side JavaScript (which is how the _ga cookie works) is capped at 7 days too. On iOS, returning visitors look like new users after a week. Server-set first-party cookies via Set-Cookie headers are not capped the same way. SST lets you set those.
Ad blockers
uBlock Origin and friends block google-analytics.com, googletagmanager.com, and facebook.net by default. Between 20 and 40 percent of technical audiences run an ad blocker. SST serves tags from your own domain (for example metrics.yourbrand.com), which blockers leave alone.
Consent and compliance
Client-side tags fire before consent is granted, then get "suppressed" by Consent Mode. Server-side tagging lets you enforce consent at the server boundary. Nothing leaves the server until signals are explicitly permitted. Cleaner for audits, cleaner for DPOs.
Data ownership
With SST you see the raw payloads before they go to any vendor. You can redact PII, enrich with CRM data, or route the same event to three destinations without loading three scripts in the browser.
Core Web Vitals wins
This is the surprise benefit for most clients. A marketing site loads 6 to 12 third-party tags client-side: GA4, GTM, Meta Pixel, LinkedIn Insight, Hotjar, HubSpot, Intercom chat. Each one costs JavaScript parse time, network round trips, and a layout shift or two.
Moving these behind SST reduces total blocking time by 200 to 600 milliseconds and can shave 0.5 to 1.0 second off Largest Contentful Paint on mobile. That matters because Core Web Vitals are a ranking signal and directly affect conversion.
Architecture options
There are three realistic paths.
Google Tag Manager Server container on Google Cloud Run
Google's official path. You deploy a Docker image to Cloud Run, point a subdomain (via CNAME) at it, and configure tags in the GTM Server UI. Cost is usage-based, roughly AUD $40 to $120 per month for a site doing 100k to 500k pageviews. You manage the infrastructure.
Stape.io (or similar managed hosts)
Stape is the most popular managed SST host. They run the GTM Server container for you, handle autoscaling and SSL, and offer power-ups like Meta CAPI gateways and GA4 cookie extensions. Plans start around USD $20 per month. For most Aussie SMBs, this is the right choice. You get SST without running Docker.
Custom Node or edge function
For teams with engineering capacity, a bespoke endpoint on Vercel, Cloudflare Workers, or Fastly Compute is cheaper, faster, and fully under your control. You build your own event schema, forward to GA4 Measurement Protocol and Meta CAPI yourself. More flexible, more maintenance.
Implementation on Next.js
On a Next.js site, the cleanest pattern is:
- Install
@next/third-partiesfor the client GTM snippet, pointed at your SST endpoint rather thangoogletagmanager.com. - Proxy the GTM container JS through a Next.js rewrite (
next.config.jsrewrites) from/metrics/gtm.jsto your SST host. This keeps the request on your own origin. - For server-sent events (backend-triggered conversions, webhooks), POST directly from a Route Handler to the SST endpoint using a shared secret header. This lets Stripe or HubSpot webhooks feed the same analytics pipeline as the browser.
- Use the
X-Gtm-Server-Previewheader in dev mode to hit GTM Server's preview environment without polluting production.
Implementation on Gatsby
Gatsby sites are mostly static, which simplifies the picture.
- Use
gatsby-plugin-google-tagmanagerwith theincludeInDevelopment: falseflag and point thedataLayerNameat the SST loader. - Configure a custom subdomain (for example
metrics.yourbrand.com) via your CDN. On Netlify this is a rewrite in_redirects; on Cloudflare Pages it is a Worker route. - Set
selfHostedOriginin the plugin config to load the GTM JS from your SST host instead ofgoogletagmanager.com. - Fire events via
window.dataLayer.push()as usual. The client code does not change, only where it loads from.
First-party cookies done right
The biggest single win from SST is setting the GA4 _ga and _ga_XXXX cookies server-side via Set-Cookie headers with HttpOnly omitted (GA4 needs to read them in JS) and a two-year Max-Age. On Safari, this can lift the reported returning-user count by 30 to 50 percent over a few months. It is not magic. Those users were always there. They were just invisible to your old setup.
When it is overkill
SST is not free. It adds a deployment, a monthly cost, and a failure domain. For a small business site doing under 10,000 monthly visitors, running basic GA4 with no ad spend and no compliance pressure, client-side tagging is fine. Revisit the decision once you have real money riding on attribution, or once you are running paid social at scale and need reliable Meta CAPI delivery.
What to test before going live
A broken SST setup is worse than no SST. Your analytics goes silent and nobody notices until the end-of-month report. Before swapping production traffic over, we run through a short checklist.
- Load the site in Chrome with the Network tab filtered to your SST domain. Confirm the GTM library loads from
metrics.yourbrand.comand notgoogletagmanager.com. - Fire a test conversion and check that GA4 DebugView picks it up, then confirm it appears in the GA4 real-time report within a minute.
- Check that the Meta Events Manager shows the matching server event with a strong event match quality score (above 7.0 is healthy).
- Clear cookies, reload, and verify first-party cookies are set by the server with
Set-Cookieand a two-yearMax-Age, not by client-side JavaScript. - Run the site through PageSpeed Insights before and after. Total blocking time should drop noticeably on mobile.
Only once all five pass do we switch DNS or feature-flag the new loader on for the full audience. Done properly, this takes a day of careful QA and saves weeks of chasing phantom data issues later.
Getting started
At CodeDrips, we build Gatsby and Next.js sites with SST as a standard option for clients doing serious marketing. If your analytics data feels flaky or your pixels keep breaking, let's talk about moving your tagging server-side.



