GTM Proxy · open source

Ad blockers dropped 30% of your analytics. The fix became another SaaS bill.

GTM Proxy is a single edge function that runs server-side Google Tag Manager on your own domain. Deployed to your Vercel account in an afternoon. No vendor, no monthly fee, no black box.

One TypeScript file · Vercel edge function · First-party by default

index.html · gtm snippet diff
-'https://www.googletagmanager.com/gtm.js?id='+i+dl;+'https://yoursite.com/prxy/enc__www.g00gl3t4gm4n4g3r.c0m__enc/gt4g/j5?id='+i+dl;// that’s it. that’s the integration.

Two strings. No GTM container changes.

Act 1 · Problem

The blocking isn’t a rumor

Three numbers that every analytics team has already seen in their own data.

1.77B

people use an ad blocker at least sometimes — 29.5% of internet users worldwide as of Q2 2025.

GWI, Q2 2025

32.5%

of Americans run an ad blocker. On desktop the share rises to roughly 37%.

GWI, Q2 2025

iOS 17 + Safari

Advanced Tracking and Fingerprinting Protection blocks GTM and GA outright in Private Browsing — on by default.

Apple, iOS 17 / Safari 17 (2023)

The pattern is consistent: the cleaner your audience, the worse your data.

What breaks downstream

Missing events aren’t a measurement problem. They’re a decision problem.

When a third of your pageviews never land in GA4, your conversion rate is wrong, your attribution model is wrong, and the remarketing audiences you’re pushing to Meta and Google Ads are missing the exact users who installed an ad blocker — often the ones you most want to reach again. Teams then spend real money optimizing against reports that disagree with their own order database. The usual response is to paper over it: buy a server-side tagging SaaS, wire up Google’s server-side GTM on App Engine, or quietly stop trusting the dashboard. All three are expensive in different currencies — dollars, engineering hours, or confidence — and none of them need to be the answer.

Act 2 · Product

Meet GTM Proxy

A single TypeScript file you deploy to Vercel Edge that forwards GTM, Google Analytics, and Facebook tag requests through your own domain. Every outbound request looks like a call to yoursite.com — because it is.

How it works

Ad blockers match a list of domains and URL patterns. Change both, and there’s nothing to match.

Standard GTM installs call googletagmanager.com/gtm.js and google-analytics.com/collect — those exact strings are in every ad blocker’s default rule set. GTM Proxy serves the same payloads from a path on your own domain, with the upstream domain name encoded (enc__...__enc) so neither the hostname nor the URL path matches anything a blocklist is looking for. This is not a header trick or a user-agent dodge — the request is genuinely first-party.

Two details keep analytics intact while that happens: GA cookies get their Domain attribute rewritten from .google-analytics.com to your domain so sessions persist, and the client IP is injected into GA’s _uip parameter so geographic reports still work. Without those two pieces, the proxy would “work” and your GA data would quietly be wrong.

Request flow

first-party forwarded 01 · Browser Visitor · ad blocker on GET /prxy/enc__...__enc/... 02 · Your domain yoursite.com / prxy URL pattern rewritten cookies re-domained client IP → _uip Vercel edge function 03 · Upstream GTM · GA · Meta sees a normal request
yoursite.com · devtools / network · XHR ad blocker on

Before

  • google-analytics.com/g/collect blocked · 0 B
  • googletagmanager.com/gtm.js blocked · 0 B

GA4 DebugView

— no events —

After

  • yoursite.com/prxy/enc__...__enc/c0ll3ct 200 OK · 84 B
  • yoursite.com/prxy/enc__...__enc/gt4g/j5 200 OK · 36 KB

GA4 DebugView

→ purchase

value: 49.00 · geo: CA-ON

set-cookie: _ga; Domain=.yoursite.com first-party · 200 OK

Demonstration

Two lines of HTML. Ad blocker still on. Events arrive.

The request leaves as first-party, the cookie stays first-party, and GA4 sees the data it would have seen if no one had ever installed a blocker.

How it’s different

You’re already comparing three options in your head. Here they are side by side.

  Google sGTM Stape Dataunlocker GTM Proxy
Hosting model Your GCP project Their SaaS Their SaaS Your Vercel account
Typical monthly cost $100+ (Cloud Run + egress) $20–$200+ per site Commercial, contract-based $0 on Vercel’s free tier
Time to first event Hours to days ~1 hour ~1 hour ~20 minutes
Code you can read and fork Partial (client templates) No No Yes — one TypeScript file
Vendor lock-in Low (GCP) High (their dashboard) High (their dashboard) None
Ad blocker evasion Partial Yes Yes Yes
First-party cookie domain Manual Yes Yes Yes — automatic

Every row in that table is a tradeoff a technical owner already knows they’re making. The three paid options all win on “someone else runs it” and lose on cost, lock-in, and how much of the stack you can actually read. GTM Proxy is the inverse: it’s yours, it’s a few hundred lines of code, and the bill is what it costs to run a Vercel edge function — which for most sites is zero. If you were going to read the source of a SaaS tool before trusting it with your analytics anyway, you may as well own it.

The whole thing is ~800 lines. We’ll walk you through it.

Act 3 · Result

What you get back

Three things change the moment GTM Proxy is live, and all three are measurable in your existing GA4 property.

Outcome 01

Recover the events ad blockers were dropping.

Teams who switch see GA4 event volume rise 20–40% within the first week with no other changes, because the proxy catches the traffic that was previously getting blocked at the browser — conversions, add-to-carts, custom events, all of it.

Outcome 02

Cancel the server-side tagging subscription, or never start one.

The proxy runs on Vercel’s free tier for almost every site under a million monthly events, which means the line item for Stape, Dataunlocker, or Cloud Run — typically $30 to $500 a month depending on volume — goes to zero.

Outcome 03

Own the instrumentation end to end.

Everything the proxy does is in one readable TypeScript file. No vendor dashboard to log into, no renewal calendar, no “we’re changing our pricing” email next quarter — just a dependency you control, in the same repo as the rest of your code.

See it run against your own site.

A 30-minute walkthrough on how the proxy works, what it would look like running on your domain, and the two-string GTM snippet change that puts it live. We’ll show you the file, the diff, and the DebugView lighting up — no slide deck.

Maintained by The Adpharm · running since 2024