FullVision
Tracker Setup

First-Party Tracker Proxy

Serve the FullVision tracker through your own domain to bypass URL-based ad-blockers and use first-party HttpOnly cookies

Reverse-proxy the tracker through your own domain. Same data, your domain — bypasses URL-based ad-blockers and switches identity from a JS cookie to a first-party HttpOnly cookie that survives Safari ITP and cookie-clearing scripts.

Use it when a meaningful share of your visitors run an ad-blocker, or when your audience is heavily Safari and you are losing visitors between one visit and the next.

Who needs this

You probably do if you sell to a technical audience, if your Safari traffic shows far more first-time visitors than returning ones, or if your pageview counts read low against another analytics tool.

You probably don't if you are just getting started. The standard install collects the same data with one script tag and no infrastructure change. Come back here when you have a reason to.

Prerequisites

Your workspace must have cookie_domain set before first-party cookies can be scoped to your domain. Configure it in the dashboard's tracker settings if it's not already.

Step 1 — Pick a path prefix

Choose a path you'll mount under your own domain. Free-form, alphanumerics + - / _ / / only, max 64 chars.

Avoid predictable strings — /analytics, /stats, /tracker, /tracking get added to ad-blocker filter lists over time, which defeats the point.

Good prefixes: /insights, /api/m, /r, /i, /m, /p.

Set it in the dashboard. The dashboard persists it on the workspace; it's only read at verify time.

Step 2 — Add a reverse-proxy rule

Mount /<PREFIX>/* on your domain and forward to https://db.fullvision.io/*. Your proxy rule must do three things:

  • Set Host: db.fullvision.io.
  • Forward X-Forwarded-For (so we can geo-locate the visitor).
  • Stamp X-FV-Proxy: 1 on every forwarded request. This header is what switches the request into first-party mode — ingest reads it per-request, so there is no separate "activate" step and no workspace-level flag. Requests that arrive without it are handled in plain direct mode.

Replace <PREFIX> with your chosen prefix (no leading slash on the placeholder — keep the existing slashes in each snippet).

{
  "rewrites": [
    { "source": "/<PREFIX>/:path*", "destination": "https://db.fullvision.io/:path*" }
  ]
}

The trailing slashes on the Nginx location and proxy_pass directives are required — they tell Nginx to strip the prefix before forwarding upstream.

A plain vercel.json rewrite cannot add the X-FV-Proxy request header (rewrites forward headers as-is; the headers config only sets response headers). The proxy will pass traffic through, but it stays in direct mode. To run first-party mode on Vercel, stamp the header in Edge Middleware (middleware.ts):

middleware.ts
import { NextRequest, NextResponse } from "next/server";

export function middleware(req: NextRequest) {
  const url = new URL(req.url);
  const PREFIX = "/<PREFIX>";
  if (!url.pathname.startsWith(PREFIX + "/")) return NextResponse.next();
  const upstream = new URL(url.pathname.slice(PREFIX.length) + url.search, "https://db.fullvision.io");
  const headers = new Headers(req.headers);
  headers.set("Host", "db.fullvision.io");
  headers.set("X-Forwarded-For", req.headers.get("x-forwarded-for") ?? req.ip ?? "");
  headers.set("X-FV-Proxy", "1");
  return fetch(upstream, { method: req.method, headers, body: req.body });
}

export const config = { matcher: "/<PREFIX>/:path*" };

Step 3 — Update your tracker <script> tag

Swap the src from db.fullvision.io to your own domain plus the prefix. Keep the same publishable key (pk_…).

<!-- BEFORE -->
<script async src="https://db.fullvision.io/t.js?k=pk_..."></script>

<!-- AFTER -->
<script async src="https://<your-domain>/<PREFIX>/t.js?k=pk_..."></script>

Step 4 — Verify in the dashboard

Click Verify in the dashboard. This is a pre-flight check — it calls GET /v1/proxy/verify against your prefix (using your cookie_domain + proxy_path_prefix) and confirms:

  • The tracker script (/t.js) is reachable through your prefix
  • The ingest endpoint is reachable through your prefix
  • The query string survives the rewrite (auth depends on it)
  • Your proxy forwards the visitor IP via X-Forwarded-For

If anything fails, the dashboard surfaces the specific reason — see Troubleshooting below.

There is no separate "activate" step. First-party mode turns on the moment your proxy starts stamping X-FV-Proxy: 1 — it's decided per request, not by a workspace flag. Verify just confirms the chain is wired correctly before you point real traffic at it.

Step 5 — Confirm end-to-end

Load a real page on your site. The dashboard shows the new pageview within seconds. If you don't see it, jump to Troubleshooting.

What changes in first-party mode

  • FullVision takes your visitor IP from X-Forwarded-For[0] (instead of the connection IP, which would be your proxy's egress).
  • FullVision resolves country server-side via geoip-lite, same as before.
  • POST /v1/i returns 200 with a { visitor_id } JSON body and sets an HttpOnly Set-Cookie scoped to your cookie_domain (instead of returning 204 and letting the browser write a JS cookie).
  • Cross-pageview stickiness now survives Safari ITP, browser extensions that wipe document.cookie, and the JS-clearing scripts some sites bundle accidentally.

Troubleshooting

Rollback

There's no dashboard switch to flip — first-party mode is per request, so rollback means making your proxy stop stamping X-FV-Proxy. Two ways:

  • Drop the header — remove the X-FV-Proxy line from your proxy rule. The next ingest hit falls back to direct mode immediately; the proxy keeps passing traffic through, just on the direct-mode path.
  • Revert the <script src> — point it back at db.fullvision.io/t.js?k=… so traffic skips the proxy chain entirely.

Either is sufficient on its own. Reverting the <script src> is the cleaner full rollback; dropping the header is the fastest if you can't redeploy the page.

FAQ & edge cases

On this page