Proxy the Admaxxer pixel through a Cloudflare Worker
A Cloudflare Worker on four exact routes forwards the pixel's requests from your domain to Admaxxer, so your visitors' browsers never contact admaxxer.com. The Worker also passes along each visitor's country, which a proxy would otherwise hide.
Self-run proxy · Cloudflare Workers · Advanced
Prefer nothing to deploy? A managed first-party subdomain does the same job with one DNS record; the comparison below helps you choose.
Why route the pixel through your own domain
- Requests stay on your domain. The script and every event go to your own hostname, so blockers and DNS filters that work from lists of tracking hostnames have no admaxxer.com request to match.
- A simpler Content Security Policy. Both requests are same-origin, so
'self'already covers them. See CSP troubleshooting. - Always the current pixel. You forward the script instead of copying it, so pixel updates reach your visitors with no re-install.
What it doesn't change
Visitors who opt out stay opted out, and tools that inspect scripts on your own pages can still interfere. A proxy also changes which network address Admaxxer sees — read what Admaxxer sees through your proxy before you switch.
Before you start
- Your site's DNS record is proxied through Cloudflare (orange cloud). Worker routes only run on proxied hostnames.
- Permission to create Workers and routes for that zone. Each forwarded request counts as a Worker request on your Cloudflare plan.
- Your Admaxxer Website ID (it starts with
admx_), from the pixel install page.
What your proxy must forward
With data-proxy-origin set, the pixel sends every request to that address instead of admaxxer.com. Forward each of these paths to the same path on https://admaxxer.com. A proxy that forwards only some of them silently loses data: custom events, purchases and identify calls each travel on a path of their own.
| Path on your site | What uses it | Forward it |
|---|---|---|
/pixel.js | The tracking script | Required |
/api/event | Pageviews, time on page, checkout-return detection, email identification and the install check | Required |
/api/event/batch | Custom events, goals and purchases, sent in small batches | Required |
/api/identify | admaxxer.identify(userId, traits) for signed-in users | Required if you identify users |
/api/pixel/adblocker-probe/<website ID> | window.admaxxer.probe(), only if your own code calls it | Optional |
Pass requests through unchanged (same method, same JSON body), addressed to admaxxer.com in both the Host header and the TLS server name. Two browser headers must survive the trip:
User-Agent. Requests without one are treated as bots and quietly discarded.OriginorReferer. Admaxxer only accepts events from your site's domains; with neither header, events are rejected with a403.
Cookies aren't needed: the pixel sends its visitor and session IDs inside the request body.
Already using one of these paths?
The pixel appends these paths to whatever
data-proxy-originyou give it, so you can keep everything under a folder. Withdata-proxy-origin="https://yourdomain.com/admx"and the script at/admx/pixel.js, the pixel calls/admx/api/event,/admx/api/event/batchand so on. Forward each one to the same path on admaxxer.com without the/admxprefix.
Step 1: Create the Worker
In the Cloudflare dashboard, create a new Worker (under Workers & Pages) and replace its code with:
src/index.js
// Forwards the Admaxxer pixel's requests from your domain to Admaxxer.
const UPSTREAM = "https://admaxxer.com";
const FORWARD = new Set(["/pixel.js", "/api/event", "/api/event/batch", "/api/identify"]);
export default {
async fetch(request) {
const url = new URL(request.url);
if (!FORWARD.has(url.pathname)) {
// Not a pixel path: let your site handle it as usual.
return fetch(request);
}
// Same method, body and headers (including User-Agent, Origin and Referer).
const upstream = new Request(UPSTREAM + url.pathname + url.search, request);
// Admaxxer can't see the visitor's address through a proxy, so pass the country.
if (request.cf && request.cf.country) {
upstream.headers.set("X-Real-Country", request.cf.country);
}
return fetch(upstream);
},
};
- Only the four pixel paths are forwarded; anything else that reaches the Worker goes to your site unchanged.
new Request(…, request)keeps the method, body and headers, soUser-Agent,OriginandRefererarrive at Admaxxer as the browser sent them.X-Real-Countrycarries the visitor's two-letter country code from Cloudflare, so your location reports stay accurate.
Step 2: Add the routes
In the Worker's settings (Domains & Routes), add one route per path, using the exact hostname your pages are served from. Add the www. versions as well if your site answers on both.
Routes
yourdomain.com/pixel.js
yourdomain.com/api/event
yourdomain.com/api/event/batch
yourdomain.com/api/identify
Prefer Wrangler? The same Worker and routes as configuration, deployed with npx wrangler deploy:
wrangler.toml
name = "pixel-proxy"
main = "src/index.js"
compatibility_date = "2025-01-01"
routes = [
{ pattern = "yourdomain.com/pixel.js", zone_name = "yourdomain.com" },
{ pattern = "yourdomain.com/api/event", zone_name = "yourdomain.com" },
{ pattern = "yourdomain.com/api/event/batch", zone_name = "yourdomain.com" },
{ pattern = "yourdomain.com/api/identify", zone_name = "yourdomain.com" },
]
Step 3: Update your pixel snippet
Replace the Admaxxer snippet on every page with this version. Use your own Website ID (it starts with admx_; copy it from the snippet on the pixel install page) and the exact hostname your pages load from, such as www.yourdomain.com if that is your site's address.
<script async
src="https://yourdomain.com/pixel.js"
data-website-id="admx_your_website_id"
data-proxy-origin="https://yourdomain.com">
</script>
srcloads the script through your proxy.data-proxy-originsends every event through your proxy. Without it the script still loads from your domain, but events go straight to admaxxer.com.- It's the same snippet Admaxxer generates for a managed first-party subdomain; only the hostname differs.
Replace, don't add
Keep exactly one Admaxxer snippet per page. If two load, only the first one runs, so a leftover standard snippet can keep sending events to admaxxer.com.
Using Pro tracking or another script variant
/pixel.js always serves the standard script. To use another variant, such as script.plus.js for Pro tracking, forward /js/script.plus.js instead of /pixel.js and point src at https://yourdomain.com/js/script.plus.js. Leave data-proxy-origin as it is: every variant reads it.
Step 4: Check that it works
Run these from any terminal, replacing yourdomain.com with your site's hostname:
# 1. The script loads through your domain: expect HTTP 200 and a JavaScript content type
curl -sI https://yourdomain.com/pixel.js
# 2. Each endpoint reaches Admaxxer. An empty body is rejected on purpose,
# so nothing is recorded; the error reply proves the route works.
curl -s -X POST https://yourdomain.com/api/event -H 'Content-Type: application/json' -d '{}'
# expect: {"error":"validation_failed", ...}
curl -s -X POST https://yourdomain.com/api/event/batch -H 'Content-Type: application/json' -d '{}'
# expect: {"error":"empty_batch"}
curl -s -X POST https://yourdomain.com/api/identify -H 'Content-Type: application/json' -d '{}'
# expect: {"error":"validation_failed", ...}
Only Admaxxer answers with those error messages. If you get your own site's 404 page or HTML instead, that path isn't being forwarded.
Then load your site with the browser's developer tools open on the Network tab. The script and the api/event requests should go to your own domain (none to admaxxer.com), and accepted events are answered with 202. Finally, open the pixel install page: the Verify install card turns green once events arrive.
What Admaxxer sees through your proxy
Visitors and sessions are counted from the IDs the pixel sends, so those numbers don't change. What changes is the network address: Admaxxer uses the address of whatever connects to it, and through a self-run proxy that is your proxy, not your visitor. Forwarding headers such as X-Forwarded-For are not used for this.
- Country. Read from a country header when one arrives with the request (
CF-IPCountry,X-Vercel-IP-CountryorX-Real-Country, holding a two-letter country code). Otherwise it is looked up from the connecting address, which through a proxy is your proxy's location. The Worker in Step 1 already sendsX-Real-Country, so countries resolve to your visitors' locations. - Rate limit. Each network address can send up to 100 requests every 10 seconds to a site. Through a proxy your visitors share your proxy's address, so a busy site can reach that limit at peak times; requests over it are rejected with
429and those events are lost. - Excluding your own traffic. IP-based exclusion rules can't match visitors through a proxy. To keep your own visits out, run
admaxxer.optOut()in your browser's console on your site (see the consent API). - Server-side purchase matching. When a purchase captured by the pixel is passed on to ad platforms, the shopper's network address is one of the match signals. Through a proxy it is your proxy's address, which can lower match quality.
Troubleshooting
- Your own 404 page or HTML instead of Admaxxer's reply. The forwarding rule isn't matching that path. Check the exact path and hostname, and that the rule sits ahead of any catch-all rule.
403withorigin_not_allowed. TheOriginandRefererheaders aren't reaching Admaxxer, or the page's domain isn't one of your site's domains in Admaxxer.- Requests answer
204but no pageviews appear.204means Admaxxer received the event and deliberately dropped it, most often because theUser-Agentheader was removed (requests without one are treated as bots). A204is also normal for the once-a-day install check and for visitors who opted out. 429responses. Your combined traffic reached the per-address rate limit described in what Admaxxer sees.- Every visitor shows the same country. No country header is reaching Admaxxer; see what Admaxxer sees.
- The Worker never runs. Check that the DNS record is proxied (orange cloud, not DNS only) and that each route's hostname matches the address in your browser exactly, including
www..
Self-run proxy or managed subdomain?
Admaxxer can also serve the pixel from a subdomain of yours with no proxy to run: in Integrations, open First-party tracking domain, add a subdomain such as t.yourdomain.com and create the one DNS record it shows. Both options load the pixel and send events from your own domain.
| Managed first-party subdomain | Self-run proxy (this guide) | |
|---|---|---|
| Hostname | A subdomain, such as t.yourdomain.com | The hostname your site already uses |
| What you set up | One CNAME record | Forwarding rules on your server, CDN or framework |
| Who keeps it running | Admaxxer | You |
| Snippet | Shown in Admaxxer once DNS is verified | Written by you, from this guide |
Choose a self-run proxy when you can't add DNS records, don't want a separate tracking subdomain, or need every request to pass through infrastructure you control. Otherwise the managed subdomain is less to maintain; see the first-party tracking domain guide.
Undo the setup
Put the standard snippet back first (copy it from the pixel install page), then delete the four routes (or the Worker). In that order, no page ever points at a path that has stopped working.
Same setup on another platform: NGINX · Apache · Vercel · Next.js · Netlify · Nuxt · WordPress
Frequently asked questions
Q: Do I need this if I set up a first-party tracking domain in Admaxxer?
No, use one or the other. Both make the pixel load and report from your own domain. The managed subdomain is set up in Admaxxer with one DNS record; a self-run proxy runs on your own server, CDN or framework.
Q: Will this stop ad blockers from blocking Admaxxer?
It removes admaxxer.com from every request, which is what hostname-based block lists match on. Blockers that inspect scripts or paths on your own site can still interfere, and visitors who opt out stay opted out.
Q: Do I need the X-Real-Country lines?
They're optional but recommended. Without them Admaxxer may only see the network location the Worker connects from, so visitors can appear in the wrong country.
Q: Will the Worker slow down the rest of my site?
Only requests matching the four routes run the Worker; every other request to your site is untouched.
Q: Can I download pixel.js and host the file myself?
You can, but you'd stop receiving pixel updates. Forwarding the script keeps it current automatically, and the event paths have to be forwarded either way.
Related guides
- First-party tracking domain — The managed alternative: one DNS record, nothing to run yourself.
- Proxy through NGINX — Four exact-match location blocks.
- Proxy through Vercel — Four rewrites in vercel.json.
- Proxy through Netlify — Four proxy rules in _redirects.
- Install the pixel — Script variants, cookieless mode and the standard snippet.