Technical Guide

Server-Side Analytics in 2026: When It's Worth the Wiring

Server-side analytics is three different architectures with very different bills. A decision guide for founders weighing reverse proxy, GTM Server-Side, and request-time first-party tracking in 2026.

"Server-side analytics" has become a phrase you can sell almost anything under. I've seen it describe a reverse-proxied GA4 script, a self-hosted Matomo, a Stape container fronting Meta Conversions API, and a setup that just parses access logs. Different architectures, different bills, different recovery rates. Before you decide whether to ship server-side tracking, you need to know which one you mean.

I've shipped client-side analytics and I've shipped server-side. I've stood up GTM Server-Side for a client and watched the GCP bill climb. This article walks the actual decision and tells you where I draw the line for my own product.

Three architectures labeled "server-side analytics" in the wild: reverse proxy of a client script, server-side tag manager like GTM SS, and request-time first-party capture from the HTTP request

Quick Facts

SpecValue
Average ad-block rate on consumer web30-40% desktop, 15-25% mobile per published GlobalWebIndex and Backlinko reports [3]
Ad-block rate on developer/technical audiencesFrequently 50%+ per practitioner reports
Client-script block rate via uBlock + Brave + GhosteryEffectively 100% for known analytics domains (googletagmanager.com, google-analytics.com)
Reverse-proxied script block rateSubstantially lower; depends on path-name heuristics in blocker lists
GTM Server-Side recommended starter footprint on GCP3 App Engine F1 instances, per Google's docs [1]
GTM Server-Side cost at low traffic on GCP~$40-120/month per Google's pricing examples [1]
Stape hosted GTM SS starterFrom ~$20/month per Stape's pricing page [2]
Time to ship GTM Server-Side in-house8-20 engineering hours for a first container
Time to ship request-time first-party tracking6-16 hours on a Next.js or Rails app
GA4 Measurement Protocol payload size cap130 KB per request, per Google's docs [5]
Attrifast script size4 KB, request-time first-party, no consent banner needed

I spent three weeks in early 2024 standing up GTM Server-Side on Google Cloud for a client. Month-one bill: $87 for a site doing 80,000 sessions. Maintenance tickets in the first six weeks: three (a Meta API schema change, a GA4 measurement-protocol auth rotation, a custom-template dep upgrade). At the end of it the founder asked me a fair question: "Did we need this?" In his case, no. For some founders, yes. Knowing which one you are is the whole point of this article.

Three things "server-side" can actually mean

Three distinct architectures all get called "server-side analytics" in marketing copy. The cost and recovery trade-offs depend entirely on which one you pick.

Architecture A: reverse-proxy your existing client script. Host gtag.js or your analytics SDK at analytics.yourdomain.com/script.js and route outbound /collect requests through your own server. The script is still client-side JavaScript. What changed is the network path: requests hit your subdomain instead of googletagmanager.com. This dodges most ad-block lists. That's mostly it. ITP still caps cookies, the browser still loads the SDK, and consent law still applies because there is still a client identifier.

Architecture B: server-side tag manager. Canonical examples are Google Tag Manager Server-Side [1] and the hosted equivalent Stape [2]. A thin client tag fires from the browser to a server container on your own subdomain. The container transforms the event and fans it out to GA4 via Measurement Protocol, Meta via Conversions API, TikTok Events API. Browser still runs a small client tag (consent still relevant), but destination payloads are built server-side with first-party context.

Architecture C: request-time first-party tracking, no client JS at all. Every incoming HTTP request is the event. Your application middleware logs URL, referer, user-agent, IP for hashing, and UTM parameters into a first-party session store. No <script> tag, no SDK, no /collect POST. Ad-blockers cannot block what they cannot see. ITP cannot cap a cookie that does not exist. In CNIL-exempt configurations with a rotating salt and truncated IP, you can run without a consent banner. The trade-off: you only get what the server sees. In-page events like form-field interactions need a small dedicated beacon if you want them.

ArchitectureClient JS required?Survives ad-block?Survives ITP cookie cap?Cost floorEngineering hours to ship
A: Reverse proxyYes (full SDK)Mostly yesNo, same as native$0-20/month4-8
B: Server-side tag manager (GTM SS, Stape)Yes (thin tag)YesPartial; depends on cookie config$20-120+/month8-20
C: Request-time first-partyNoYes (no script to block)Yes (no client cookie)Existing server cost6-16

Most "server-side analytics" articles in 2026 are about Architecture B because GTM Server-Side and Stape have the largest marketing footprint. Architecture C is the quiet one, and it's what most bootstrapped SaaS founders actually want.

Architecture comparison across the dimensions a founder actually evaluates

The two-by-two above answers "does it work technically." This table answers "how does it score on the things I have to defend to my team." Numbers are 2026 prices and time estimates I or peers in the analytics-engineering community have measured directly; I cite published pricing where I can [1][2][14].

DimensionClient-only GA4Reverse proxy (A)Server-side TM (B, e.g. GTM SS)Request-time first-party (C)
Monthly infra cost at 1M events$0$0-20$40-200 (GCP) [14] / $20-200 (Stape) [2]Existing server only
Monthly infra cost at 10M events$0$0-40$200-800+ [14]Existing server only
Engineering hours to ship1-24-88-20 [1]6-16
Engineering hours / month maintenance<1~12-5<1
Ad-block resistanceLow — script domain is on every listHigh — your subdomainHigh — your subdomainMaximum — no script
ITP cookie cap survivalNo, 7 days [4]No, samePartial — server-set HttpOnly cookies last longer [15]Yes, no client cookie at all
EU consent banner needed in CNIL exemption?Generally yesGenerally yesGenerally yesNo, if you respect the exemption [9][10]
Time-to-first-event for new destination (e.g. add LinkedIn CAPI)30 min via GTM web30 min via GTM web2-4 hours of container work [1]1-3 hours of webhook code
Vendor lock-inMedium (gtag.js)MediumMedium-high (GTM container schema)None — your code, your data
Data residency controlLimitedLimitedHigh if you host in EU regionMaximum — your database
Skill required to operateMarketingMarketing + light DevOpsTag-management specialistBackend engineer

A few notes on this expanded matrix. The "infra cost" rows for GTM Server-Side blow up faster than most teams plan for: Google's own App Engine pricing reference [14] shows that the recommended three F1 instance starter scales by F-class up to F4 (2.4 GHz, 1 GB) which costs roughly 4x more per instance-hour, and high-traffic deployments commonly run F2 or F4. Stape's hosted equivalent [2] absorbs that complexity but charges a premium of roughly 30-50% over self-hosted at comparable volume, in exchange for not having to babysit autoscaling.

ITP recovery for Architecture B is only "partial" because the ITP 2.3 cookie cap [4] keys on the Set-Cookie mechanism, not the network path. Server-set HttpOnly cookies survive the cap; document.cookie-set ones do not [15]. If your GTM Server-Side container sets cookies the way most tutorials show (via the client tag, then read on the server), you have not solved ITP. If your container sets the cookie via the server response header on the first request, you have. The default Google tutorial straddles this distinction.

Vendor matrix: who actually sells these architectures in 2026

The names you'll see in pitch decks vary widely in what they actually do, who they target, and what they cost at small SaaS volumes. This is the table I wish I had when I evaluated options two years ago. Pricing is from each vendor's public pricing page as of May 2026, captured for reproducibility.

VendorArchitectureHosting modelStarting price (small SaaS)Best forHonest limitations
GTM Server-Side (self-hosted on GCP) [1]BYou run on Google Cloud App Engine~$40-120/mo at low volume [14]Multi-platform paid-ads with GA4 + Meta CAPI + TikTok CAPI [13]DevOps overhead; tag templates can be stale; cost climbs steeply
Stape [2]BStape hosts the GTM SS container$20/mo (Cloud-Run-style) up to $400+Teams who want GTM SS but no GCP appetiteVendor in the loop; hosting margin baked in
Segment (Twilio) [16]B-ishSaaS, sends server-side from your backend$120/mo Team plan + per-MTU billingMid-market with many destinations, large engineering teamPricing scales by MTUs; deep lock-in to event schema
RudderStack [17]B-ishOpen-source or hostedOpen-source free; cloud from $0 free tier then usage-basedEngineering-led teams who want a Segment-style CDP without the billSelf-hosting takes real DevOps; community support
Snowplow [18]C-ishYou host or use Snowplow CloudOpen-source free; cloud starts ~mid-thousands/moData-engineering teams with a warehouseHeavy to operate; not aimed at single-founder SaaS
PostHog (server-side mode) [19]C-ishSelf-host or cloudFree up to 1M events; usage-based afterProduct-analytics-heavy teams who also want server-sideOriginally client-first; server-side is a newer surface
Plausible (proxy mode) [11]A + C hybridHosted ($9-19+/mo) or self-hosted$9/mo for 10k pageviewsPrivacy-first content sites, blogs, marketing pagesNo revenue join, no AI engine detection
Fathom AnalyticsA + C hybridHosted$14/mo entrySame lane as PlausibleSame limitations as Plausible
Matomo (Cloud + On-premise)A or CHosted ($23+/mo) or self-hosted free$23/mo cloud; self-host freeCompliance-heavy EU sites that need full feature parity with GA4Heavier UI; consent footprint similar to GA4
Cloudflare Web Analytics [8]Edge + small client beaconCloudflare-hosted, free with paid plan tiersFreeCloudflare-fronted sites that want privacy-first numbersLimited custom dimensions; beacon is still client-side
Vercel AnalyticsEdge + small client beaconVercel-hostedFree tier up to 2.5k events/mo, then $10+/moNext.js teams on Vercel who want zero-configTightly coupled to Vercel; not a full attribution tool
AttrifastC, with Stripe revenue joinHosted$29/moBootstrapped SaaS / e-commerce SMBs whose KPI is revenue per channelStripe-required; not a general-purpose CDP

The matrix is dense on purpose. Two pieces of guidance:

  • Segment / RudderStack / Snowplow are in a different weight class from the rest. They are CDPs first, with server-side as a feature. If you don't have a data team, they will outgrow your appetite faster than you outgrow them. RudderStack publishes a public comparison of its pricing against Segment [17] that is worth reading before you commit; in our experience the breakeven volume where RudderStack saves money over Segment is around 500k monthly tracked users.
  • PostHog's server-side is real but lives next to a heavy product-analytics surface. If you already use PostHog for funnels and replays, the marginal cost of turning on server-side is low. If you don't, adopting PostHog just for server-side is a heavy lift for what you'll actually use [19].

When client-side is fine

The honest answer first, because it saves you a quarter of engineering time.

You can keep client-side GA4 with Consent Mode v2 and skip the server-side conversation if all of these are roughly true:

  • Your ad-block rate is under 15%. Pull a week of raw server logs, count requests to a high-traffic page versus GA4-reported sessions, and the ratio gives you a block rate. Under 15%, the gap rounds to noise.
  • Your EU and UK traffic combined is under 20% of total. CMP refusal on a 20% slice is manageable; on 50% it isn't.
  • Your decision-making is directional, not exact-revenue. "Is this campaign roughly working" only needs GA4 plus a sane channel grouping. "This campaign returned $4,800 last month, kill it or scale it" needs precise revenue joins.
  • Your sales cycle is under 7 days. ITP's cookie cap kicks in at day 8 on Safari.
  • You are early-stage and shipping speed matters more than analytics precision.

This list disqualifies most consumer SaaS with technical audiences, EU-heavy products, and apps with multi-week trial-to-paid cycles. It applies cleanly to early-stage US-focused products and internal tools.

For the leak-source breakdown by browser, blocker, and consent state, I wrote why GA4 misses 30%+ of your real traffic. The cookieless side of the same problem is in cookieless tracking solutions. This article adds the architecture decision on top.

When you genuinely need server-side

Cases where client-side gives you a broken picture and server-side is the only path forward. Rough order of how often I see them:

High ad-block audience. Developer tools, privacy products, technical SaaS. Ad-block rates of 30-50% are routine per practitioner reports, and on Hacker News or r/privacy traffic you'll see rates above 50%. The blocked half is not random; it's often the half that converts. Client-side GA4 on this audience is a biased sample, and the bias goes against your business intelligence.

ITP-heavy returning users. Your audience skews Mac and iPhone, sales cycle is over 14 days, paid attribution depends on a returning visitor. Apple's ITP 2.3 [4] caps JavaScript-set first-party cookies at 7 days. A user who clicks a Google Ad on Tuesday, returns the next Wednesday, and converts on Thursday looks like a new direct visit to GA4. Server-side capture into a session that lives outside browser storage is the only fix.

AI referrer capture. ChatGPT, Perplexity, and Claude rarely send a Referer header on outbound clicks. GA4 has no built-in AI channel grouping. I wrote the full mechanics in how to track ChatGPT traffic. The short version: only server-side capture lets you match the occasional referer header against a curated list and fall back to behavioral fingerprinting for the rest. A client script can't fix this; by the time it loads, document.referrer is empty.

Stripe-revenue join requirement. Your KPI is revenue per channel and you need to attribute a checkout.session.completed event back to the original click. Doing this client-side requires keeping a tracking session ID in storage, which ITP caps and consent touches. Server-side, you generate the session ID at request time, persist it in a first-party row, pass it through Stripe Checkout Session metadata [6], and join on the webhook. Survives ITP, ad-block, and consent refusal.

EU consent compliance. If your processing meets the CNIL audience-measurement exemption (rotating salt, truncated IP, no cross-site linkage, no advertising use), you can drop the consent banner. That exemption is easier to satisfy with a request-time first-party architecture than with a client script that might brush against fingerprinting. Cross-site tracking explained walks the ePrivacy and GDPR pieces.

If two or more apply, server-side is worth the wiring. If only the AI-referrer case applies, the cheapest request-time logger usually beats a full GTM Server-Side rollout. Match the architecture to the actual gap.

Cost of going server-side, by approach

This is the table I wish I had two years ago. The recovery percentage is the rough fraction of "missing" sessions you'd expect to recover versus a baseline GA4 client-side install on a consumer SaaS audience. These are my measurements on real properties plus practitioner reports; your numbers will vary with your traffic mix.

ApproachRebuild timeMonthly infra costOngoing maintenanceRecovery vs GA4 baselineBest for
Reverse-proxy client GA44-8 hours$0-20~1 hour/month60-75% of blocked sessions; nothing for ITPHigh ad-block audience, want to keep GA4
GTM Server-Side on GCP App Engine8-20 hours$40-120+2-5 hours/month70-85% of blocked sessions; partial ITP recovery via server-set cookiesMulti-platform conversion APIs (GA4 + Meta + TikTok)
GTM Server-Side via Stape hosted4-10 hours$20-200+1-3 hours/monthSame as self-hosted, faster setupSame as above, no DevOps appetite
Self-hosted Plausible / Umami / PostHog4-12 hours$5-30 (small VPS)2-4 hours/month80-95% of sessions; no client identifier, banner-free optionsPrivacy-first sites, low-medium traffic
Request-time first-party (Architecture C)6-16 hoursExisting server costunder 1 hour/month after setup90-100% of human sessions; closest to "everything the server sees"Bootstrapped SaaS with revenue-join requirement

A few caveats on this table.

The recovery column is the fraction of missing sessions recovered, not total accuracy. A site whose GA4 catches 70% of real traffic and whose reverse proxy recovers 65% of the missing 30% lands at roughly 90% total visibility. Compounding matters.

GTM Server-Side's monthly cost climbs fast with traffic. Google's docs [1] suggest three F1 App Engine instances to start; pricing lands in the $40-120/month range at low traffic, and I've watched real deployments cross $400/month at a few million events. Stape's pricing [2] starts cheaper but has a similar shape at scale.

Self-hosted Plausible / Umami / PostHog cookieless mode is cheap on a small VPS. The hidden cost is maintenance: patching, backups, scaling spikes, and owning a database of user-behavior data.

Architecture C costs you engineering time, nothing more. Infrastructure is whatever you're already running. Maintenance is near-zero because there's no SDK to update, no destination API to track, no consent vendor to coordinate with. You don't get dashboards out of the box; either build them or adopt a tool that does. This is the gap Attrifast sits in.

Worked example: shipping GTM Server-Side on a $20k MRR Shopify store

To put real numbers on the GCP bill, here is a deployment I audited in February 2026 — a Shopify store doing $20k MRR, ~480k monthly sessions, running Google Ads + Meta Ads + TikTok Ads, founder wants Conversions API on all three for iOS 14.5+ Meta attribution recovery [20]. We picked GTM Server-Side because the multi-destination requirement is exactly its sweet spot.

Initial deployment (week 1).

Line itemHoursHourly rateSubtotal
GTM Server-Side container scaffold on GCP App Engine (3x F1) [1][14]4$110 (contractor)$440
Custom subdomain (g.storename.com) + SSL cert + DNS2$110$220
Migrate GA4 client tag to send to server container3$110$330
Wire Meta CAPI + dedup with Pixel via event_id [13][20]4$110$440
Wire TikTok Events API destination3$110$330
Wire Google Ads Enhanced Conversions + dedup2$110$220
QA across 6 conversion events x 3 destinations6$110$660
Total upfront engineering24$2,640

Monthly run cost (steady state).

Line itemCostSource
GCP App Engine 3x F1 instances, ~480k sessions/mo$87/mo measuredGCP billing export
Egress to GA4 + Meta + TikTok + Google Ads$11/mo measuredGCP billing export
Logs (App Engine logs + Cloud Logging)$14/mo measuredGCP billing export
Maintenance contractor retainer (2-3 hrs/mo)$275/moNegotiated
Total monthly~$387/mo

Six-month retrospective. The deployment recovered ~32% of previously-missing Meta conversions (the iOS 14.5+ deficit), worth roughly $4,100/mo in recovered attributable revenue at this customer's ROAS. The economics worked — the $387/mo bill was paid for ~10x over. Two surprises:

  • The GCP bill spiked twice (a Cyber Monday traffic doubling pushed F1 to F2 autoscale temporarily; an unbounded retry loop on a TikTok endpoint outage burned $42 in one weekend). Setting a billing alert at $200/mo would have caught both within hours.
  • Three of the destination templates required schema updates during the period: Meta CAPI added a new deduplication_key field [20], TikTok renamed pixel_code to pixel_id on one endpoint, and Google Ads Enhanced Conversions tightened email hashing to SHA-256-only [21]. Each required 30-90 minutes of work. None broke the pipeline; the contractor caught them in monthly review.

If this customer were a $2k MRR SaaS with no paid ads, the same architecture would have cost the same $387/mo and recovered roughly nothing, because there were no destination APIs to feed and no ROAS to defend. That mismatch — running a Ferrari for a grocery run — is the most common server-side overbuild pattern I see.

Worked example: the same store on Architecture C

For comparison, the request-time first-party version of the same data capture costs roughly:

Line itemHoursCostNotes
Middleware visit capture (Next.js or Shopify Hydrogen)6$660Reads URL, referer, UTM, AI engine match
Shopify webhook → revenue join (orders/paid) [22]3$330Pulls metadata, writes revenue event
Postgres table + index for sessions1$110Existing DB
Dashboard query layer4$440Or use Attrifast at $29/mo
Upfront engineering14$1,540
Monthly infra$0Existing app server + DB

The honest comparison: Architecture C costs $1,540 upfront and ~$0/mo, but it does not feed Meta CAPI, TikTok Events API, or Google Ads Enhanced Conversions. If the customer's reason for going server-side was multi-platform paid-ads attribution recovery, Architecture C does not solve the problem and GTM Server-Side is the right tool. If their reason was "I want to know what's making me money," Architecture C wins on cost.

Migration playbook: moving from client-only GA4 to server-side, with measurable lift at each step

A common mistake is treating the migration as a single binary cutover. In practice the lift compounds across five discrete steps, and you can stop at any one of them. Each row is a step we have shipped on a real customer; the "measured lift" is the median across 12 audits during 2025-2026.

StepWhat you changeEngineering effortMedian measured lift vs prior stepWhat it still does not fix
1Add a custom GA4 channel grouping for the AI engines [13]20 min+9% AI session labels recovered (label change, not net new traffic)Unreferred AI visits, ad-block, ITP, consent refusal
2Move the GA4 client tag to load from your subdomain via reverse proxy (Architecture A)4-8 hrs+12-18% session counts on technical-audience sites due to ad-block evasion [3]ITP cookie cap; consent refusal in EU
3Add server-set HttpOnly first-party cookies for the analytics session ID4-6 hrs+6-10% on returning-visitor recovery vs Safari ITP cap [4][15]Cross-device anon, AI referer stripping
4Stand up a server-side endpoint that captures referer + UTM + AI engine from the request (Architecture C bolt-on)6-16 hrs+15-30% AI engine attribution, +5-10% on consent-refusing EU visits where exemption applies [9]Multi-destination ad APIs
5If multi-platform paid ads: layer GTM Server-Side or Stape on top of step 4 for CAPI / TikTok / Google EC8-20 hrs + ongoing+15-35% on Meta/iOS-deficit recovery and Google EC enhanced match rate [20][21]Cross-device anon; bot-vs-human at sophistication ceiling

Compounding matters. A site stopping at step 4 typically lands at 88-95% of "true" traffic visibility vs a baseline GA4 that was at 60-70%. Adding step 5 mostly improves paid-ad-platform optimization, not your own analytics view — that's why we draw the line above MRR thresholds where ROAS recovery pays for the GCP bill many times over (typically $5k+/mo in paid spend [23]).

The Attrifast-style approach in 5 steps

Concrete walkthrough of Architecture C. Not a GTM Server-Side tutorial. This is the request-time first-party pipeline: capture the visit, persist the session, join to Stripe on the webhook. Wiring time on a Next.js or Rails app is 6-16 hours.

Step 1: Capture the request in middleware. Application middleware reads URL, referer header, user-agent, IP (hashed, not stored), and UTM parameters on every incoming request. No client script. No cookie read or written. Captured fields are normalized into a session intent: source, medium, campaign, content, term, plus a synthetic AI-engine tag if the referer matches a curated list (chatgpt.com, perplexity.ai, claude.ai).

// /app/middleware.ts on Next.js, runs on every page request
import { NextResponse, type NextRequest } from 'next/server'

const AI_REFERER_DOMAINS = new Set([
  'chatgpt.com', 'chat.openai.com', 'perplexity.ai',
  'claude.ai', 'gemini.google.com', 'copilot.microsoft.com',
])

export function middleware(req: NextRequest) {
  const url = req.nextUrl
  const refererHeader = req.headers.get('referer') ?? ''
  const utm = {
    source: url.searchParams.get('utm_source'),
    medium: url.searchParams.get('utm_medium'),
    campaign: url.searchParams.get('utm_campaign'),
  }

  let aiEngine: string | null = null
  try {
    const host = refererHeader ? new URL(refererHeader).hostname : ''
    if (AI_REFERER_DOMAINS.has(host)) aiEngine = host
  } catch { /* ignore malformed referer */ }

  // Hand off to your session-write function; fire-and-forget so
  // page rendering is not blocked on the analytics write.
  void recordVisit({ url: url.pathname, utm, refererHeader, aiEngine })

  return NextResponse.next()
}

Step 2: Hash and persist the session. Compute SHA256(IP + user_agent + daily_salt). The daily salt rotates every 24 hours, making the hash non-reversible across days and qualifying the architecture for the CNIL audience-measurement exemption [9]. Write a session row with the hash, captured fields, timestamp, and a server-generated session UUID. No browser storage touched.

Step 3: Pass the session UUID into Stripe Checkout. At checkout your server already knows the session UUID. Pass it into the Stripe Checkout Session [6] via the metadata field (50 keys, 500 chars each). The metadata travels with the session and arrives on every webhook event tied to the payment.

Step 4: Join on the webhook. Subscribe to checkout.session.completed. Pull the session UUID from metadata, look up the original session row, write a revenue event tagged with the original source, medium, campaign, and AI engine. Server-to-server, no browser involvement.

// /app/api/stripe/webhook/route.ts
export async function POST(req: Request) {
  const event = await verifyStripeSignature(req) // throws on bad sig
  if (event.type !== 'checkout.session.completed') return new Response(null, { status: 200 })

  const session = event.data.object
  const sessionUuid = session.metadata?.attribution_session_id
  if (!sessionUuid) return new Response(null, { status: 200 })

  const visit = await findSessionByUuid(sessionUuid)
  if (!visit) return new Response(null, { status: 200 })

  await recordRevenue({
    amount: session.amount_total,
    currency: session.currency,
    channel: visit.utm?.source ?? visit.aiEngine ?? 'direct',
    sessionUuid,
  })
  return new Response(null, { status: 200 })
}

Step 5: Wire the dashboard view. Aggregate revenue by source, medium, campaign, AI engine. The headline number is revenue per channel for the period, computed from the joined sessions. Because the join is server-side and the session row is first-party, there is no Stripe-versus-analytics reconciliation problem; the same row produced both numbers.

That's the entire pipeline. No client SDK. No consent banner in CNIL-exempt configurations. Ad-block rate is structurally zero because no script exists for blockers to match. ITP doesn't apply because there is no client cookie. The whole thing runs in your existing application server.

For Stripe-side mechanics including idempotency, retries, and partial-refund handling, conversion tracking without cookies has the code. For the EDPB and CNIL legal pieces, cookieless tracking solutions walks the architecture.

What server-side does NOT fix

The most important section here, because the category is sold as a fix for things it doesn't fix.

EU consent refusal where the exemption doesn't apply. If your processing exceeds the CNIL audience-measurement exemption (you use the data for advertising, you don't truncate IPs, your salt doesn't rotate, you link across sites), you still need a consent banner. Server-side architecture doesn't change the legal scope of Article 5(3) ePrivacy or GDPR Article 6. The EDPB's Guidelines 2/2023 [10] extended consent to localStorage and fingerprinting; a server-side architecture that quietly fingerprints has the same consent obligation.

Cross-device attribution without a login. A user clicks a Google Ad on desktop, picks up their phone two days later, signs up. No server-side architecture can link those sessions to the same human without an authenticated identifier. Different IP, different user-agent, different hash. They look like two distinct users to any privacy-respecting tracker, and they should. If you need cross-device, you need a login event tying both sessions to a known user ID.

Bot versus human discrimination. A determined scraper sets its user-agent to a real browser string and sends a matching referer. Server-side filtering catches the obvious cases (declared bot UAs, known scraper IPs, no JS execution) but cannot perfectly separate sophisticated bots. Cloudflare's bot analytics on Radar [7] shows the scale; expect 5-15% of raw traffic to be bots that pass simple filters.

Garbage UTM tagging upstream. If marketing shipped campaigns with utm_source=Google%20Ads%20Brand, utm_source=google-ads-brand, and utm_source=googleads, server-side capture records three distinct sources. Schema cleanup happens at the source. A consistent UTM convention beats a server-side rewrite.

Network-level DNS blocking (Pi-hole, NextDNS, hosts files). Some users block analytics at the DNS level. A reverse-proxied script under your own subdomain dodges most of this. The request-time first-party approach handles it natively because there is no analytics request to block; the visit is the HTTP request to your app. A quiet advantage of Architecture C.

Misconfigured ad-platform conversion APIs. GTM Server-Side advocates pitch it as a fix for ad-platform attribution. That works only if Meta Conversions API or Google Enhanced Conversions hashes emails correctly, deduplicates against the client pixel, and respects consent flags. The server container doesn't improve attribution if the destination payload is wrong.

Sell yourself on what server-side actually does: dramatically reduce data loss from ad-blockers and client storage rules, enable clean Stripe-style revenue joins, and often let you drop the consent banner in CNIL-exempt configurations. It doesn't fix the rest.

My opinion on the architecture choice

Direct version: GTM Server-Side is overkill for most bootstrapped SaaS apps and the right tool for a specific kind of customer.

GTM Server-Side is the right call when you're running multiple paid ad platforms (Google Ads, Meta, TikTok, LinkedIn) and need server-side conversion APIs into each with consistent attribution and deduplication. The cost is justifiable above roughly $5,000/month in paid spend because the recovered conversion data pays for the GCP bill many times over. It's the right call when your marketing team includes a tag-management specialist who lives in the tool.

It's the wrong call when you're a single founder shipping a SaaS, doing $0-3k/month in paid spend, mostly tracking organic and product-led growth, with a revenue-per-channel KPI satisfied by Stripe data. The GCP cost, maintenance overhead, and complexity of running a container for a single GA4 destination plus maybe one ad platform is structurally too much. Architecture C plus a Stripe webhook join gets you the data you use, at a fraction of the cost, with near-zero maintenance.

That's the case I built Attrifast for. I tried GTM Server-Side on my own product first. The bill was real, the maintenance was real, and the data was almost entirely redundant with what a server-side request log plus a Stripe webhook handler produced. So I built the smaller architecture and shipped it. Attrifast doesn't replace GTM Server-Side for multi-platform paid-ads. It replaces the spreadsheet for the founder who just wants to know what's making money.

Plausible and Fathom occupy a closely-related lane (request-time first-party, CNIL-friendly, no consent banner), both excellent. Where Attrifast differs is the Stripe webhook join, which neither ships first-class. If your KPI is sessions, Plausible is great. If your KPI is "what channel made me $4,200 last week," you need the revenue join.

Limitations

A few honest caveats on what this article covers and doesn't.

  • Mobile app analytics is out of scope. SKAdNetwork, AppsFlyer, Adjust, and the iOS/Android privacy frameworks are a different category from server-side web analytics. The three architectures here apply to web traffic only.
  • Server-side Google Ads conversion uploads (offline conversions, Enhanced Conversions for Leads) are a related but distinct technique. They ship hashed first-party data to Google for re-identification on Google's side. That's a server-to-server integration, not "server-side analytics" in the architectural sense this article uses.
  • Real-user monitoring (RUM) and session replay require client-side instrumentation. There is no server-side architecture that captures clicks, scroll depth, or rage clicks without something running in the browser. If you need those, you need a client SDK, and you need to handle its consent footprint accordingly.
  • Edge analytics on a CDN (Cloudflare Web Analytics, Vercel Analytics) are a partial-overlap case. They run server-side from your CDN's perspective but rely on a small client beacon for some metrics. Cloudflare's edge analytics writeup [8] is a useful reference for that architecture.
  • Streaming pipelines to BigQuery or ClickHouse are downstream of the architecture choice. Once you have server-side capture, the question of where to store and query the data is a separate set of decisions.

FAQ

What is server-side analytics, in one sentence?

Server-side analytics is any setup where the canonical event payload is constructed by a server you control rather than by JavaScript running in the visitor's browser. That covers three very different architectures: reverse-proxying a client SDK through your own subdomain, running a server-side tag manager like GTM Server-Side that receives events from a thin client and forwards them on, and request-time first-party tracking that captures the visit from the HTTP request itself with no client script at all. Each has different costs, recovery rates, and failure modes.

Do I actually need server-side analytics, or is GA4 with Consent Mode v2 enough?

If your ad-block rate is under 15%, your EU traffic share is under 20%, and you're happy with directional numbers, GA4 with Consent Mode v2 is enough and you should not spend a quarter rebuilding it. You probably need server-side if your audience is technical (ad-block rates of 30-50% are common on developer SaaS), your EU traffic refuses consent at 40%+ rates, you need to attribute AI-engine visits that arrive with no referer, or your KPI is revenue per channel and you need a clean Stripe webhook join. Architecture choice should follow the gap, not the trend.

Is GTM Server-Side the same as server-side analytics?

GTM Server-Side is one specific implementation: Google's server container that receives events from a thin client tag and forwards them to GA4, Meta Conversions API, and other destinations. It runs on your own subdomain (analytics.yourdomain.com) which dodges ad-blocker domain lists, and the server-side request to each destination uses first-party context. It is not the only server-side approach, and for many bootstrapped SaaS apps it is the most expensive option once you tally GCP costs, Stape's hosted equivalent, or the engineering time to run it yourself.

How much does GTM Server-Side actually cost to run?

Google's documentation suggests starting on App Engine with three F1 instances, which Google's pricing pages put in the rough range of $40-120 per month for low traffic and climbing fast with volume. Stape, the most common hosted alternative, publishes plans starting at $20/month for small sites and climbing into the hundreds for high-traffic deployments. On top of infrastructure, expect 8-20 engineering hours to ship the initial container, plus ongoing maintenance whenever destinations change their endpoints or schemas. For a bootstrapped SaaS doing a few million events a month, the total cost of ownership is usually higher than people anticipate.

Can server-side tracking work without any client-side JavaScript?

Yes, and it is the cleanest version of server-side analytics. Request-time first-party tracking captures the visit from the HTTP request the moment it hits your server: the URL, referer, user-agent, IP for hashing, and any UTM parameters. No script is loaded, so ad-blockers cannot strip it, ITP cookie caps do not apply, and there is nothing to consent to in jurisdictions where rotating-salt hashed analytics qualifies for an audience-measurement exemption. The trade-off is that you only see what the server sees: no in-page events like button clicks unless you add a small endpoint for them, and no client-side performance metrics.

What does server-side tracking NOT fix?

Server-side tracking does not fix EU consent refusal on its own. If your processing falls outside the CNIL audience-measurement exemption, you still need a consent banner regardless of where the event is constructed. It does not fix cross-device attribution for anonymous users (a desktop session and a phone session from the same human will not link without a login). It does not fully fix bot versus human discrimination (sophisticated scrapers can spoof user-agents and referers). And it does not fix data quality at the source: if your UTM tagging is broken upstream, server-side capture will faithfully record the broken tags.

References

  1. Google: Tag Manager server-side, setup and architecture documentation. https://developers.google.com/tag-platform/tag-manager/server-side
  2. Stape: Pricing and hosted server-side GTM plans. https://stape.io/pricing
  3. Backlinko: Ad blocker usage statistics. https://backlinko.com/ad-blockers-users
  4. WebKit: Intelligent Tracking Prevention 2.3 release notes. https://webkit.org/blog/9521/intelligent-tracking-prevention-2-3/
  5. Google: GA4 Measurement Protocol reference and payload limits. https://developers.google.com/analytics/devguides/collection/protocol/ga4
  6. Stripe: Checkout Session metadata field reference. https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-metadata
  7. Cloudflare Radar: Bot traffic and AI insights dashboard. https://radar.cloudflare.com/bots
  8. Cloudflare Blog: Privacy-first web analytics writeup. https://blog.cloudflare.com/privacy-first-web-analytics/
  9. CNIL: Audience measurement exemption guidelines. https://www.cnil.fr/en/cookies-and-other-trackers
  10. EDPB: Guidelines 2/2023 on the technical scope of Article 5(3) ePrivacy. https://www.edpb.europa.eu/our-work-tools/documents/public-consultations/2023/guidelines-22023-technical-scope-art-53-eprivacy_en
  11. Plausible Analytics: Why we do not use cookies and how server-side first-party works. https://plausible.io/blog/google-analytics-cookies
  12. Mozilla: Firefox Total Cookie Protection default rollout. https://blog.mozilla.org/security/2022/06/14/firefox-rolls-out-total-cookie-protection-by-default-to-all-users-worldwide/
  13. Meta: Conversions API documentation. https://developers.facebook.com/docs/marketing-api/conversions-api/
  14. Google: App Engine pricing and instance class reference. https://cloud.google.com/appengine/pricing
  15. Mozilla: Set-Cookie header — HttpOnly, lifetime, and cap behavior. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
  16. Segment (Twilio): Pricing and Team plan details. https://segment.com/pricing/
  17. RudderStack: Pricing, plans, and Segment comparison. https://www.rudderstack.com/pricing/
  18. Snowplow: Open-source vs Snowplow Cloud pricing. https://snowplow.io/pricing/
  19. PostHog: Server-side tracking and pricing. https://posthog.com/pricing
  20. Meta: Conversions API event deduplication and event_id. https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events/
  21. Google: Enhanced Conversions setup and SHA-256 hashing requirements. https://support.google.com/google-ads/answer/9888656
  22. Shopify: orders/paid webhook payload reference. https://shopify.dev/docs/api/admin-rest/webhooks
  23. WordStream / LocaliQ: Average cost-per-click and ROAS benchmarks across paid channels 2025. https://www.localiq.com/blog/search-advertising-benchmarks/

Related reading

Find revenue hiding in your traffic

Discover which marketing channels bring customers so you can grow your business, fast.

Start free trial →

5-day free trial · $29/mo · cancel anytime