Background
⌘K

Tracking Through Your Own Domain

Proxy the Affonso pixel, click tracking, and signup tracking through your own domain to improve tracking accuracy.

Silvestro
Written by Silvestro
Updated more than a week ago

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 pathForward toRequired for
/r/pixel.jshttps://cdn.affonso.io/js/pixel.min.jsPixel installs
/r/psl.min.jshttps://cdn.affonso.io/js/psl.min.jsPixel installs
/r/trackhttps://api.affonso.io/v1/trackClick tracking
/r/signupshttps://api.affonso.io/v1/signupsSignup tracking

Notes:

  • keep the suffixes exactly as shown
  • only the prefix is configurable
  • if you do not use signup tracking, /r/signups can 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

  1. Open https://customer.com/r/pixel.js and confirm it returns JavaScript.
  2. Load a page with the updated pixel script.
  3. Visit your site with ?atp=test.
  4. In DevTools, confirm the browser sends a request to /r/track.
  5. 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-base matches the prefix exactly
  • Confirm POST /r/signups is 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.

Next Steps

Was this article helpful?

If you still need help, our support team is here for you.

Contact Support
bg

Ready to Scale Your SaaS?

Affonso is the easiest way to launch your own affiliate program. We take care of the technical stuff, so you can focus on growing your business.