Sign up

Proxy

Serve tracking from your own domain

A same-origin proxy can help when extensions block third-party tracker URLs. It exposes only the public script and collection endpoint, never your secret key.

Set up a proxy (Next.js App Router)

  1. Add a route handler

    app/a/[kind]/route.ts
    // app/a/[kind]/route.ts — Next.js App Router
    import { NextRequest } from "next/server";
    
    async function proxy(req: NextRequest, context: { params: Promise<{ kind: string }> }) {
      const { kind } = await context.params;
      const script = kind === "script" && req.method === "GET";
      const event = kind === "event" && req.method === "POST";
      if (!script && !event) return new Response("Not found", { status: 404 });
      const headers = new Headers();
      for (const name of ["content-type", "origin", "user-agent"]) {
        const value = req.headers.get(name);
        if (value) headers.set(name, value);
      }
      // Trust these only if your hosting provider overwrites them.
      const ip = req.headers.get("cf-connecting-ip") || req.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
      if (ip) headers.set("x-visitor-ip", ip);
      for (const [source, target] of [["cf-ipcountry", "x-visitor-country"], ["cf-region", "x-visitor-region"], ["cf-ipcity", "x-visitor-city"]]) {
        const value = req.headers.get(source);
        if (value) headers.set(target, value);
      }
      const upstream = await fetch(script ? "https://metricraven.com/js/script.js" : "https://metricraven.com/api/v1/collect", {
        method: req.method, headers, body: event ? await req.arrayBuffer() : undefined,
        cache: "no-store", signal: AbortSignal.timeout(15000),
      });
      return new Response(upstream.body, { status: upstream.status, headers: {
        "Content-Type": upstream.headers.get("content-type") || "application/octet-stream",
        "Cache-Control": script ? "public, max-age=3600" : "no-store",
      }});
    }
    export { proxy as GET, proxy as POST };
  2. Replace your script tag

    Point the script and its events at your own paths:

    index.html
    <script defer src="/a/script" data-api="/a/event" data-site-id="YOUR_SITE_ID"></script>
  3. Forward the real visitor IP

    Use a header your hosting provider sets and overwrites. Forwarding your server's own IP gives misleading locations. If Cloudflare supplies visitor location headers, forward those too.

Verify it works

In the Network panel, requests to /a/script and /a/event succeed, and new visits show plausible countries.

Details

  • A proxy doesn't guarantee that every blocker will allow tracking.
  • Any server can proxy the same way: serve https://metricraven.com/js/script.js, forward events to https://metricraven.com/api/v1/collect, and pass the visitor IP as x-visitor-ip (plus x-visitor-country, x-visitor-region and x-visitor-city if known).