Tracking
Proxy the script through your domain
Serve the Revfaro script and its event endpoint from your own domain so ad blockers don't drop your visitors, with Next.js, Vercel, nginx or Cloudflare Workers.
In short
Some ad blockers stop analytics scripts loaded from another domain. Forward two paths on your own domain to Revfaro (the script and the event endpoint), point the script at them with data-api, enable First-party proxy in Tracking settings, and let your authenticated proxy pass on the visitor's User-Agent and IP address. Payments are never affected by ad blockers, because they arrive by webhook from your payment provider.
On this page
Ad blockers keep lists of analytics domains and block scripts loaded from them. When the script and the endpoint it sends to live on your own domain, most blockers let them through.
How the proxy works
You forward two paths on your domain to Revfaro:
| Path on your site | Forwards to |
|---|---|
/stats/script.js |
https://revfaro.com/js/script.js |
/stats/event |
https://revfaro.com/api/event |
You can pick any path. Neutral names such as /stats/ work better than words blockers look for, like analytics or tracking.
Events then reach Revfaro from your server. The proxy must send:
- the
User-Agentheader, and - the visitor's IP address, in
X-Revfaro-Visitor-IP,X-Vercel-Forwarded-For, orX-Forwarded-For(in that order), and - your site's proxy key, in
X-Revfaro-Proxy-Secret.
Revfaro needs the address for IP exclusions, cookieless visitors and its per-visitor limits, and never stores it.
Location reporting: Revfaro only trusts Cloudflare location information for the connecting visitor. When your proxy forwards a visitor's address, Cloudflare sees the proxy, so Revfaro leaves the visitor's location unknown. Vercel location headers are not used. For location reporting, send events directly to Revfaro's Cloudflare-protected hostname.
Set up the proxy
In Website settings → Tracking, enable First-party proxy and copy the proxy key into a server-only environment variable named REVFARO_PROXY_SECRET. Never put it in HTML, browser code, or a NEXT_PUBLIC_ variable. Without the matching key, forwarded IP headers are ignored and the sender gets the direct-visitor limit.
Next.js on Vercel
Use a rewrite for the script and a server route for events. A plain event rewrite cannot add your private proxy key. On Vercel, read its platform-provided X-Vercel-Forwarded-For header; do not copy an untrusted browser header as the visitor IP.
module.exports = {
async rewrites() {
return [{ source: '/stats/script.js', destination: 'https://revfaro.com/js/script.js' }];
},
};export async function POST(request) {
const response = await fetch('https://revfaro.com/api/event', {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
'User-Agent': request.headers.get('user-agent') ?? '',
'X-Vercel-Forwarded-For': request.headers.get('x-vercel-forwarded-for') ?? '',
'X-Revfaro-Proxy-Secret': process.env.REVFARO_PROXY_SECRET,
},
body: await request.text(),
});
return new Response(null, { status: response.status });
}nginx
For nginx that receives your visitors' connections itself. Behind another proxy or load balancer, pass the address it resolved instead of $remote_addr.
location = /stats/script.js {
proxy_pass https://revfaro.com/js/script.js;
proxy_ssl_server_name on;
}
location = /stats/event {
proxy_pass https://revfaro.com/api/event;
proxy_ssl_server_name on;
proxy_set_header X-Revfaro-Visitor-IP $remote_addr;
proxy_set_header X-Revfaro-Proxy-Secret "YOUR_SERVER_ONLY_PROXY_KEY";
proxy_set_header Cookie "";
}Cloudflare Workers
A Worker on your site's route, in front of your origin. Store REVFARO_PROXY_SECRET as a Worker secret:
export default {
async fetch(request, env) {
const { pathname } = new URL(request.url);
if (pathname === '/stats/script.js') return fetch('https://revfaro.com/js/script.js');
if (pathname === '/stats/event') {
return fetch('https://revfaro.com/api/event', {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
'User-Agent': request.headers.get('User-Agent') ?? '',
'X-Revfaro-Visitor-IP': request.headers.get('CF-Connecting-IP') ?? '',
'X-Revfaro-Proxy-Secret': env.REVFARO_PROXY_SECRET,
},
body: await request.text(),
});
}
return fetch(request);
},
};Then change your script tag: load the script from your domain and send events there with data-api:
<script defer data-website-id="YOUR_SITE_ID" data-api="/stats/event" src="/stats/script.js"></script>Deploy, open your site and check that a request to /stats/event returns 202 in your browser's Network tab. Verify your installation has the details.
Limits behind a proxy
Every visitor behind your authenticated proxy gets the same limit as a visitor who connects directly: 1,200 events every 10 minutes per website. On top of that, one proxy address can forward up to 30,000 events every 10 minutes for one website.
If your proxy doesn't pass the visitor's address, everything arrives from your server's address: IP exclusions can't match visitors, cookieless mode counts everyone with the same browser as one visitor, and a busy site reaches the per-address limit quickly. Always forward the correct address; a proxy server's location is not a visitor's location.
Serve the cookieless script
The same setup works for cookieless mode: point the script path at https://revfaro.com/js/script.cookieless.js and keep everything else as it is. Keep the authenticated event server route; a script rewrite alone does not forward your visitors' addresses.
For self-hosted Revfaro behind Coolify, the deployment proxy must also preserve and validate the sender address. See the deployment guide: Traefik can replace forwarded headers by default. A site proxy key does not configure your infrastructure proxy.
Frequently asked questions
Do ad blockers affect revenue tracking?
Payments themselves are always recorded, because Stripe, Dodo Payments, Lemon Squeezy and Polar send them to Revfaro by webhook. What a blocked script costs you is the visit, so the payment may not be linked to a source.
Why does my proxy need to pass on the visitor's IP address?
Revfaro uses it for IP exclusions, cookieless visitors and its per-visitor limits, and never stores it. Without it, events arrive from your server's address and all your visitors look like one visitor there. Forwarded visits have an unknown location.
Can I proxy the cookieless script?
Yes. Point the script path at /js/script.cookieless.js instead. Make sure your proxy passes on the visitor's IP address, because cookieless mode recognizes visitors by it.