Docs

First-party proxy

By default the browser talks to the 3x API host directly. A first-party proxy routes the same requests through a path on your own domain, e.g. https://example.com/n3/….

Why

  • Ad blockers block third-party analytics hosts; measured losses without a proxy are typically 5–25 % of visits. A path on your own domain is not on block lists (avoid words like analytics, tracking, stats or the product name in the path – /n3 is the default).
  • Visitor separation: sessions are stitched with a hash of IP and user agent (Cookieless sessions). A proxy that does not forward the visitor's IP makes everyone look like the proxy server. The 3x proxy protocol forwards the IP authenticated, so the API can trust it.
  • CSP: everything becomes same-origin (script-src 'self'; connect-src 'self').

The protocol

host maps 1:1 onto the API root, so a proxy at /n3 forwards /n3/v1/e to <api>/v1/e. Only four path families are forwarded:

PathMethodPurpose
/v1/e (and /v1/collect)POST, OPTIONSEvent batches (text/plain JSON)
/v1/c/{pk}GETClient configuration
/v1/cbPOSTConversion beacon
/v1/s/{file}GETSDK scripts (cache them: public, max-age=3600, stale-while-revalidate=86400)

For each forwarded request the proxy:

  1. removes cookie and authorization – the proxy never sends your site's cookies to 3x;
  2. forwards user-agent, origin, content-type and the body unchanged;
  3. adds x-3x-client-ip (the visitor's IP: first x-forwarded-for entry, x-real-ip, cf-connecting-ip or the socket address – whatever your platform guarantees), x-3x-client-country (x-vercel-ip-country, cf-ipcountry, if available) and x-3x-proxy-key (your proxy key, from server-side configuration).

The API trusts x-3x-client-* only when x-3x-proxy-key is a valid key with the scope ingest:proxy for the project of the batch. A wrong or revoked key is rejected with 403, so a misconfiguration is visible immediately rather than silently merging visitors.

The proxy key

Create it in Project → Settings → Keys → Proxy keys (POST /v1/projects/{project}/proxy-keys, scope project:admin; or the MCP tool setup_generate_snippet with proxy: true). It is a secret key that can do nothing except vouch for forwarded IPs of this one project. Keep it in your server's environment (X3_PROXY_KEY), never in the browser. Roll it like any key (Authentication and keys).

Recipes

PlatformRecipe
Next.js (App or Pages Router), any Fetch-API runtimeNext.js route handler
Cloudflare (any site behind Cloudflare, Webflow, static hosting)Cloudflare Worker
Nginx, Apache-fronted serversNginx
NetlifyNetlify edge function
WordPressWordPress REST route
No server access at allCNAME subdomain

What does not work

Plain rewrites (vercel.json rewrites, next.config.js rewrites, Netlify redirects with status

  1. cannot add headers. They are fine for the script (/v1/s/*), but event POSTs through them

arrive with the CDN's IP – on a Vercel-hosted API the forwarded IP is overwritten – and visitors get merged. The dashboard warns when more than 30 % of a day's sessions share one visitor hash.