Ad blockers hide part of your analytics. How to measure it and serve analytics first-party
If your audience is developers, designers or anyone tech-savvy, a noticeable share of them run an ad blocker. Most blockers don't only hide ads: they also stop analytics scripts from loading. Those visitors don't show up in your dashboard at all, so you under-count traffic and the gap differs by channel.
Why analytics gets blocked
Blockers such as uBlock Origin, AdGuard and the built-in shields in Brave use filter lists. Lists like EasyPrivacy contain the domains and paths of common analytics tools. When the page asks for a script from a listed domain, the request is simply cancelled.
The lists match on the request URL, not on what the script does. That's why the same script, served from your own domain under a neutral path, usually loads fine.
How much are you missing?
It depends heavily on the audience. Mainstream consumer sites lose a small share; developer tools and tech blogs often lose much more. Rather than trusting someone else's average, measure your own:
- Compare with server logs. Count page requests from real browsers in your web server or CDN logs for one day and compare with the pageviews in analytics. Logs include bots, so filter obvious crawlers first. This gives a rough upper bound.
- Run both for a week. Keep the normal script and add a proxied copy on the same pages (with a separate site, so the numbers don't mix). The difference between the two is your blocked share.
- Look by channel. Visits from Hacker News, GitHub or Reddit are typically blocked far more often than visits from Google Search. If your analytics says "developers don't come from Hacker News", check this first.
The fix: serve the script first-party
A first-party proxy makes your own domain forward a path such as /pl/* to the analytics provider. The browser only talks to your site, so domain-based lists don't apply. The setup is one rule in most stacks.
Next.js
// next.config.js
module.exports = {
async rewrites() {
return [{ source: '/pl/:path*', destination: 'https://app.pagelens.io/:path*' }];
},
};
Nginx
location /pl/ {
proxy_pass https://app.pagelens.io/;
proxy_set_header Host app.pagelens.io;
proxy_ssl_server_name on;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Cookie "";
}
Then load the script through the proxy:
<script defer src="/pl/script.js" data-site-id="YOUR_SITE_ID"></script>
Two details matter:
- Forward the visitor's IP (
X-Forwarded-For). Otherwise every visit looks like it comes from your server's location, and visitor counts collapse. - Strip cookies. Your site's session cookies have no business going to a third party. The rules above remove them.
Recipes for Cloudflare Workers, Vercel, Netlify and Caddy are in the proxy guide.
Is this OK to do?
A proxy changes where a request goes, not what the law requires. If your analytics sets cookies or builds profiles of people, you still need consent, proxy or not, and hiding a tracker from someone who chose to block it doesn't get you that consent.
The argument for proxying is strongest when the tool itself respects privacy: no cookies, no cross-site tracking, no personal data stored, and no data used for ads. Then you're measuring visits to your own site, which is what most people who install a blocker are fine with. Mention the tool in your privacy policy either way.
Summary
- Blockers match analytics by domain and path, so the gap is real and biggest on tech audiences.
- Measure it for your own site before deciding anything.
- A first-party proxy is one rule; forward the IP and drop cookies.
- Pair it with a cookieless tool such as PageLens, so you get complete numbers without tracking people.