Proxy Pixel Tracking Through Your Own Domain
We recommend this setup for every Affonso program. It serves the tracking script and browser-visible tracking requests from your own domain, making them less likely to be blocked.
The hosted setup still works without this proxy. Use it if you cannot add a proxy yet, then switch to this setup when you can.
What This Covers
This guide proxies:
- the pixel script
- click tracking requests
- signup tracking requests
It does not proxy the embedded dashboard. That is covered separately in Proxy the Embedded Dashboard Through Your Own Domain.
Route Map
Proxy these customer-domain paths to the Affonso hosted endpoints:
| Your path | Forward to | Required for |
|---|---|---|
/r/pixel.js | https://cdn.affonso.io/js/pixel.min.js | Pixel installs |
/r/psl.min.js | https://cdn.affonso.io/js/psl.min.js | Pixel installs |
/r/track | https://api.affonso.io/v1/track | Click tracking |
/r/signups | https://api.affonso.io/v1/signups | Signup tracking |
Notes:
- keep the suffixes exactly as shown
- only the prefix is configurable
- if you do not use signup tracking,
/r/signupscan be omitted
Real Client IP
If you proxy /track or /signups, Affonso must still receive a trusted real
client IP header such as CF-Connecting-IP, True-Client-IP, or X-Real-IP.
If your proxy forwards only its own edge IP, attribution can still work while country data is wrong or missing.
Quick Setup: Cloudflare Worker
Use this if your domain is on Cloudflare. It is the recommended and shortest setup.
1. Create a Worker and add this code
export default {
async fetch(request) {
const url = new URL(request.url);
const directMap = {
'/r/pixel.js': 'https://cdn.affonso.io/js/pixel.min.js',
'/r/psl.min.js': 'https://cdn.affonso.io/js/psl.min.js',
'/r/track': 'https://api.affonso.io/v1/track',
'/r/signups': 'https://api.affonso.io/v1/signups',
};
if (directMap[url.pathname]) {
const upstream = new URL(directMap[url.pathname]);
upstream.search = url.search;
return fetch(new Request(upstream, request));
}
return fetch(request);
},
};2. Add the Worker route
In Workers & Pages → your Worker → Settings → Triggers, add:
customer.com/r/*Replace customer.com with your domain, then deploy the Worker.
3. Update the pixel script
Load the pixel from your domain and set data-api-base to /r:
<script
async
defer
src="https://customer.com/r/pixel.js"
data-affonso="YOUR_PUBLIC_PROGRAM_ID"
data-cookie_duration="30"
data-api-base="/r"
></script>4. Verify it works
- Open
https://customer.com/r/pixel.jsand confirm it returns JavaScript. - Load a page with the updated pixel script.
- Visit your site with
?atp=test. - In DevTools, confirm the browser sends a request to
/r/track. - If you use signup tracking, confirm it sends a request to
/r/signups.
If all five steps work, your first-party tracking proxy is ready.
Other Proxy Setups
All examples use /r. Keep the route suffixes unchanged. You can use another
prefix if /r conflicts with your application, but the pixel src and
data-api-base must use that same prefix.
Vercel rewrites
If your site runs on Vercel, add these rewrites:
{
"rewrites": [
{
"source": "/r/pixel.js",
"destination": "https://cdn.affonso.io/js/pixel.min.js"
},
{
"source": "/r/psl.min.js",
"destination": "https://cdn.affonso.io/js/psl.min.js"
},
{
"source": "/r/track",
"destination": "https://api.affonso.io/v1/track"
},
{
"source": "/r/signups",
"destination": "https://api.affonso.io/v1/signups"
}
]
}NGINX
If you use NGINX, add explicit locations for the Affonso routes:
location = /r/pixel.js {
proxy_pass https://cdn.affonso.io/js/pixel.min.js;
proxy_set_header Host cdn.affonso.io;
}
location = /r/psl.min.js {
proxy_pass https://cdn.affonso.io/js/psl.min.js;
proxy_set_header Host cdn.affonso.io;
}
location = /r/track {
proxy_pass https://api.affonso.io/v1/track;
proxy_http_version 1.1;
proxy_set_header Host api.affonso.io;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location = /r/signups {
proxy_pass https://api.affonso.io/v1/signups;
proxy_http_version 1.1;
proxy_set_header Host api.affonso.io;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}If your proxy stack has extra request filtering, make sure it does not strip
JSON request bodies or query strings on the tracking endpoints. If NGINX sits
behind another proxy, make sure $remote_addr is restored to the real visitor
IP first.
Troubleshooting
Clicks are tracked, but signups are not
- Confirm
data-api-basematches the prefix exactly - Confirm
POST /r/signupsis proxied if you use signup tracking - Make sure your proxy layer forwards the request body unchanged
I use Cloudflare Snippets instead of a Worker
Preserve the full request body for POST /r/track and POST /r/signups, and
keep CF-Connecting-IP or another trusted real-IP header intact.


