Add my site

Ad blockers and proxying Advanced

Some ad blockers block requests to any analytics domain, ours included, so a share of real visits never reaches us. Serving the tag from your own domain can reduce domain-based blocking, but blockers can still stop it. Managed setup needs a CNAME and assisted HTTPS activation; self-hosting uses two rewrites on your server.

Managed setup: CNAME and HTTPS

Settings → General → Ad-blocker proxy. Four steps, all on the card:

  1. Choose a subdomain of your site, like stats.acme.com. It has to be a subdomain of the verified domain, since the point is that a blocklist sees your own domain; the card refuses anything else. Avoid words blocklists match, like "analytics" or "track".
  2. Add the CNAME the card shows, at the place you manage DNS for your domain. It points the subdomain at our proxy host and is the only record you add:
stats.acme.com  CNAME  proxy.datastated.com
  1. Wait for "live". The card checks on every load and says one of three things: waiting for DNS (the subdomain does not point at us yet; changes can take a few minutes to spread), DNS is right but HTTPS is not answering, or live, which means https://stats.acme.com/js/ds.js?v=2026-09-10-consent answers with JavaScript, exactly what a visitor's browser will ask for.
  2. Swap the tag. Once it says live, replace the tag on every page with the one the card prints, which loads the script from your subdomain and sends events to it:
<script defer src="https://stats.acme.com/js/ds.js?v=2026-09-10-consent" data-site="acme.com"
  data-site-id="dst_YOUR_SITE_ID" data-api="https://stats.acme.com/api/collect"></script>

After the source release is deployed, replace an existing snippet's src URL with the revision shown here, including ?v=2026-09-10-consent. Changing the proxy's headers cannot clear an old unversioned script already cached in a visitor's browser. The released tag uses public, max-age=300, must-revalidate.

What crosses the proxy: the tag itself, cached for five minutes, and your visitors' events. The proxy forwards each event with the visitor's real address and, when its own edge stamps one, the visitor's country, so visitors are still counted apart and the country breakdown still works. Cookies are stripped in both directions, and the visitor never learns the upstream exists. Region and city are not recorded for proxied visits, only the country. Leave the subdomain box empty and save to go back to the standard tag.

Self-hosted: the two paths

If you would rather keep it on your own server, forward two paths from your domain to ours:

/stats/ds.js    ->  https://app.datastated.com/ds.js
/stats/collect  ->  https://app.datastated.com/api/collect

Then point the snippet at them with data-api:

<script defer src="/stats/ds.js?v=2026-09-10-consent" data-api="/stats/collect"
  data-site="acme.com" data-site-id="dst_YOUR_SITE_ID"></script>

Both proxy snippets need the same consent setup as the standard tag. Proxying does not override consent, Global Privacy Control or Do Not Track.

The path names are yours to pick. The rewrite rules below match the path only. Preserve the script's query string when forwarding to the upstream, and include it in any proxy or CDN cache key, so a revised URL cannot return a cached unversioned script.

Next.js example

// next.config.js
module.exports = {
  async rewrites() {
    return [
      { source: "/stats/ds.js", destination: "https://app.datastated.com/ds.js" },
      { source: "/stats/collect", destination: "https://app.datastated.com/api/collect" },
    ];
  },
};

Netlify, nginx, and friends

Netlify, in _redirects:

/stats/ds.js    https://app.datastated.com/ds.js      200
/stats/collect  https://app.datastated.com/api/collect  200

nginx:

location = /stats/ds.js   { proxy_pass https://app.datastated.com/ds.js; }
location = /stats/collect {
  proxy_pass https://app.datastated.com/api/collect;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

One limit to know: through a self-hosted rewrite our endpoint sees your server's address, not the visitor's, whatever headers you forward. The country breakdown and IP exclusions are wrong for those visits, and the per-address rate limit (120 events a minute) applies to your whole site. If that matters, use the managed proxy above, which carries the real address under a shared secret.

What this does and does not fix

Either way defeats domain blocklists, which is most ad blockers. It does not defeat a visitor who disables JavaScript, and it deliberately changes nothing about GPC or Do Not Track: a visitor asking not to be tracked is not tracked, proxied or not.

Questions? Email us at hello@datastated.com.