# First-party tracker proxy for analytics

> Proxy the AttribIQ tracker and event endpoint through your own domain using CDN, framework, or reverse-proxy examples.

Canonical page: [https://attribiq.com/guides/first-party-tracker-proxy](https://attribiq.com/guides/first-party-tracker-proxy)

Category: Implementation Guides

Last updated: 2026-06-06

Topics: proxy, tracker, first party, cdn, nginx, vercel, cloudflare, netlify, nextjs

## Summary

A first-party proxy serves the tracker script and event endpoint from your own domain while forwarding requests to AttribIQ. It is available on Growth and higher plans. Proxy both paths, keep the browser snippet pointed at local paths, and preserve forwarded IP headers only through trusted proxy infrastructure.

## What this guide covers

- Choose local proxy paths
- Proxy the tracker script and event endpoint
- Install the proxied script tag
- Verify pageviews in Realtime

A first-party tracker proxy keeps the browser-facing AttribIQ paths on your own domain.

This setup is available on Growth and higher plans. Direct install remains available on every plan.

Open project settings, choose **First-party proxy**, and select your deployment platform. The dashboard generator fills in the install key and AttribIQ upstream URLs for the current project.

The direct install uses the AttribIQ edge domain:

```html
<script async src="https://edge.attribiq.com/i/a7K4mN2qR8tP.js"></script>
```

The proxied install uses local paths on your site:

```html
<script async src="/_aiq/s.js" data-endpoint="/_aiq/e"></script>
```

Your proxy then forwards those local paths to the project-specific AttribIQ upstream URLs.

## Content Security Policy

With a first-party proxy, the browser loads the script and sends events through your own site paths. For strict CSP deployments, the browser-facing AttribIQ requirement is normally covered by your existing first-party directives:

```http
script-src 'self';
connect-src 'self';
```

The proxy server still forwards to `https://edge.attribiq.com`, but that upstream request is not controlled by the browser's CSP.

## Generated values

Use the exact upstream URLs from project settings.

| Value | Example |
| --- | --- |
| Local script path | `/_aiq/s.js` |
| Local event path | `/_aiq/e` |
| Upstream script URL | `https://edge.attribiq.com/i/a7K4mN2qR8tP.js` |
| Upstream event URL | `https://edge.attribiq.com/i/a7K4mN2qR8tP/x` |

You can choose different local paths, but keep them stable after publishing. If you change them, update the script tag and the rewrites together.

## Vercel

Add rewrites in `vercel.json`.

```json
{
  "rewrites": [
    {
      "source": "/_aiq/s.js",
      "destination": "https://edge.attribiq.com/i/a7K4mN2qR8tP.js"
    },
    {
      "source": "/_aiq/e",
      "destination": "https://edge.attribiq.com/i/a7K4mN2qR8tP/x"
    }
  ]
}
```

Vercel also supports reverse proxy rewrites to external destinations in `vercel.json`.

## Next.js

Use `rewrites()` in `next.config.js`.

```js
/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        source: "/_aiq/s.js",
        destination: "https://edge.attribiq.com/i/a7K4mN2qR8tP.js"
      },
      {
        source: "/_aiq/e",
        destination: "https://edge.attribiq.com/i/a7K4mN2qR8tP/x"
      }
    ]
  }
}

module.exports = nextConfig
```

## Netlify

Add redirects in `_redirects`.

```text
/_aiq/s.js  https://edge.attribiq.com/i/a7K4mN2qR8tP.js  200
/_aiq/e     https://edge.attribiq.com/i/a7K4mN2qR8tP/x   200
```

## Cloudflare Worker

Create a Worker route for the two local paths. Use this for Cloudflare Workers or Cloudflare Pages projects that can route selected paths through a Worker.

```js
const upstream = {
  "/_aiq/s.js": "https://edge.attribiq.com/i/a7K4mN2qR8tP.js",
  "/_aiq/e": "https://edge.attribiq.com/i/a7K4mN2qR8tP/x"
}

export default {
  async fetch(request) {
    const url = new URL(request.url)
    const target = upstream[url.pathname]
    if (!target) return fetch(request)

    const headers = new Headers(request.headers)
    headers.delete("Cookie")
    headers.set("Host", "edge.attribiq.com")
    headers.set("X-Forwarded-For", request.headers.get("CF-Connecting-IP") || "")

    const init = {
      method: request.method,
      headers,
      redirect: "manual"
    }
    if (request.method !== "GET" && request.method !== "HEAD") {
      init.body = request.body
    }

    return fetch(target, init)
  }
}
```

## Express or Node

If your app server can handle proxy routes, keep the script and event paths explicit.

```js
import express from "express"

const app = express()

app.use("/_aiq/s.js", async (_req, res) => {
  const upstream = await fetch("https://edge.attribiq.com/i/a7K4mN2qR8tP.js")
  res.type("application/javascript")
  res.send(await upstream.text())
})

app.use("/_aiq/e", express.text({ type: "*/*" }), async (req, res) => {
  const upstream = await fetch("https://edge.attribiq.com/i/a7K4mN2qR8tP/x", {
    method: req.method,
    headers: {
      "Content-Type": req.get("Content-Type") || "text/plain;charset=UTF-8",
      "X-Forwarded-For": req.ip
    },
    body: req.body
  })
  res.status(upstream.status).send(await upstream.text())
})
```

## Nginx

Forward both paths and strip cookies.

```nginx
location = /_aiq/s.js {
  proxy_set_header Host edge.attribiq.com;
  proxy_set_header Cookie "";
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_pass https://edge.attribiq.com/i/a7K4mN2qR8tP.js;
}

location = /_aiq/e {
  proxy_set_header Host edge.attribiq.com;
  proxy_set_header Cookie "";
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_pass https://edge.attribiq.com/i/a7K4mN2qR8tP/x;
}
```

## Caddy

Use explicit handlers for the script and event paths.

```caddyfile
handle /_aiq/s.js {
  rewrite * /i/a7K4mN2qR8tP.js
  reverse_proxy https://edge.attribiq.com {
    header_up Host edge.attribiq.com
    header_up Cookie ""
  }
}

handle /_aiq/e {
  rewrite * /i/a7K4mN2qR8tP/x
  reverse_proxy https://edge.attribiq.com {
    header_up Host edge.attribiq.com
    header_up Cookie ""
  }
}
```

## Apache httpd

Enable `mod_proxy` and `mod_proxy_http`, then add explicit proxy rules to the virtual host.

```apache
ProxyPreserveHost Off

ProxyPass "/_aiq/s.js" "https://edge.attribiq.com/i/a7K4mN2qR8tP.js"
ProxyPassReverse "/_aiq/s.js" "https://edge.attribiq.com/i/a7K4mN2qR8tP.js"

ProxyPass "/_aiq/e" "https://edge.attribiq.com/i/a7K4mN2qR8tP/x"
ProxyPassReverse "/_aiq/e" "https://edge.attribiq.com/i/a7K4mN2qR8tP/x"
```

## Kubernetes ingress

Prefer a small internal proxy service, then route the local paths to that service with your ingress controller. This avoids relying on brittle per-path external-origin annotations.

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: attribiq-proxy
spec:
  rules:
    - host: www.example.com
      http:
        paths:
          - path: /_aiq/s.js
            pathType: Exact
            backend:
              service:
                name: attribiq-proxy
                port:
                  number: 8080
          - path: /_aiq/e
            pathType: Exact
            backend:
              service:
                name: attribiq-proxy
                port:
                  number: 8080
```

The internal proxy service should forward `/_aiq/s.js` to the upstream script URL and `/_aiq/e` to the upstream event URL.

## CloudFront

Use two cache behaviors for `/_aiq/s.js` and `/_aiq/e` with `edge.attribiq.com` as the custom origin. Configure the behavior for `/_aiq/e` to allow `POST` and avoid forwarding viewer cookies. Use an edge function only if you need to rewrite the request URI before the origin request.

## Forwarded IP headers

Preserve `X-Forwarded-For` through proxy infrastructure that you control. AttribIQ should only honor forwarded IP headers from trusted proxy networks. For a self-hosted collector, configure:

```env
TRUSTED_PROXY_CIDRS=127.0.0.1/32,10.0.0.0/8,172.16.0.0/12
TRUSTED_PROXY_DEPTH=1
```

Do not trust arbitrary browser-sent forwarding headers on a public collector.

## Platform references

- [Vercel rewrites](https://vercel.com/docs/rewrites)
- [Next.js rewrites](https://nextjs.org/docs/app/api-reference/config/next-config-js/rewrites)
- [Netlify rewrites and proxies](https://docs.netlify.com/routing/redirects/rewrites-proxies/)
- [Cloudflare Workers fetch](https://developers.cloudflare.com/workers/runtime-apis/fetch/)
- [Nginx reverse proxy](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy)
- [Caddy reverse_proxy](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy)
- [Apache mod_proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html)
- [CloudFront origin modification](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html)

## Verify

After deploying:

1. Load `https://your-site.example/_aiq/s.js` and confirm it returns JavaScript.
2. Load a tracked page with the proxied script tag.
3. Open Realtime in AttribIQ and confirm the pageview appears.
4. Check that the project install key shows recent usage in settings.

Read [web tracker reference](https://attribiq.com/guides/web-tracker) for tracker fields and [Install AttribIQ](https://attribiq.com/guides/install-attribiq) for the checkout attribution flow.

## Frequently asked questions

### Is a first-party proxy required?

No. The direct project script is the default install. A proxy is useful when you want the browser to load the tracker from your own domain.

### Which paths should I use?

Use short, opaque paths such as /_aiq/s.js and /_aiq/e. Avoid obvious names such as analytics, tracking, stats, or pixel.

### Do I need to proxy both paths?

Yes. The script path loads the tracker. The event path receives pageviews, goals, and custom events.

### Should I forward cookies?

No. Strip or avoid forwarding cookies to AttribIQ unless you have a specific reason.
