If you run a website in 2026, there's a good chance your analytics are incomplete.
Not because the dashboard is wrong, but because a huge share of traffic never reaches it. Privacy tools block third-party analytics aggressively—even the tools that are comparatively respectful.
That creates an awkward situation: developers move away from invasive analytics, then lose visibility anyway because the browser still reads those requests as tracking.
The fix isn't to become more invasive; it's to make the implementation cleaner.
The Problem: Third-Party Domains Are Dead
Traditional analytics work like this:
- Load a script from
analytics-provider.com - Send data to
analytics-provider.com/api/collect - Hope the user's browser allows it
Adblockers maintain massive blocklists of known tracking domains. When they see a request to umami.is, plausible.io, or google-analytics.com, they kill it instantly.
Even privacy-respecting tools get caught in the middle.
The Solution: First-Party Proxying
Instead of loading analytics from a third-party domain, proxy it through your own domain so requests remain first-party from the browser's perspective.
The trick: Next.js rewrites.
Step 1: Configure Server-Side Rewrites
In next.config.ts:
async rewrites() {
return [
{
source: "/metrics/lib.js",
destination: "https://cloud.umami.is/script.js",
},
{
source: "/metrics/api/send",
destination: "https://cloud.umami.is/api/send",
},
]
}
What this does:
- Browser requests
/metrics/lib.js, Next.js fetches it from Umami's CDN server-side - Tracking data sent to
/metrics/api/sendgets forwarded to Umami's API - The browser never touches
umami.isdirectly
That shifts the implementation model without changing the privacy posture.
Step 2: Load the script from your domain
In app/layout.tsx:
<Script
src="/metrics/lib.js"
data-website-id="your-umami-website-id"
data-host-url="/metrics"
strategy="lazyOnload"
/>
Key details:
src="/metrics/lib.js"loads from your domain, not Umami'sdata-host-url="/metrics"tells the script to send data to/metrics/api/sendstrategy="lazyOnload"defers loading until after the page is interactive
It's also better for performance.
Step 3: Deploy and test
- Open your site with an adblocker enabled
- Check the Network tab in DevTools
- You should see:
metrics/lib.jsloads with a200statusmetrics/api/sendreceives POST requests- No requests to
umami.is, because everything is proxied
If those conditions are true, the setup is behaving the way it should.
Why this works (and why it's not evil)
Adblockers use domain-based filtering. They can't block /metrics/lib.js on your domain because:
- It's not on any blocklist
- It's a same-origin request, with no third-party warning
- They'd have to block your entire site to stop it
But isn't this sneaky?
Umami doesn't rely on the same invasive model as legacy analytics platforms. No cookie wall, no ad network profile, no cross-site identity stitching.
The point isn't to reconstruct individual users. It's to recover a truer picture of page views, routes, and general content performance.
That distinction matters. Privacy-friendly analytics and invasive surveillance are not the same implementation problem.
The performance bonus
There's also a practical performance upside.
When you load a script from a third-party domain, the browser has to:
- Do a DNS lookup for the external domain
- Establish a new core connection
- Negotiate TLS
- Download the script
With first-party proxying:
- Same domain, so no DNS lookup
- Existing connection with HTTP/2 multiplexing
- Already-established TLS session
The request path becomes simpler, and the script can load with less connection overhead.
Other Frameworks?
This technique works anywhere you can configure server-side rewrites:
- Vercel: Use
vercel.jsonrewrites - Netlify: Use
_redirectsornetlify.toml - Cloudflare Workers: Intercept and proxy requests
- Nginx/Apache: Configure reverse proxy rules
The concept is the same: make third-party analytics look like first-party requests.
The reality
Privacy and measurement shouldn't have to cancel each other out.
Users want stronger privacy guarantees. Product teams still need signal. The better answer is to improve the implementation, not to revert to older tracking habits.
First-party proxying gives you a cleaner middle ground: enough signal to make decisions, without abandoning the privacy standard you chose in the first place.
When large portions of traffic disappear, product decisions get noisier. Better data doesn't solve judgment, but it removes the blind spots.
Try it yourself
If you're using Next.js and want to add Umami:
- Sign up at umami.is — the free tier is generous
- Add the rewrites to
next.config.ts - Add the script tag to your layout
- Deploy and watch your real traffic numbers come in
That's the real goal: analytics that stay useful without turning into something users need to defend themselves against.
