Sign up

Proxy

Proxy with Vercel

On this page

vercel.json rewrites your two paths to a small Vercel Function, which forwards the visitor's IP and location.

Set it up

  1. Add the function

    Works for any framework or a static site deployed to Vercel. On Next.js, use the Next.js route handler instead.

    api/metricraven.js
    // api/metricraven.js · Vercel Function for any framework or a static site
    async function relay(request) {
      const kind = new URL(request.url).searchParams.get("kind");
      const script = kind === "script" && request.method === "GET";
      const event = kind === "event" && request.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 = request.headers.get(name);
        if (value) headers.set(name, value);
      }
      // Vercel overwrites x-forwarded-for with the visitor's IP, so it can't be spoofed.
      const ip = request.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
      if (ip) {
        headers.set("x-visitor-ip", ip);
        for (const [source, target] of [
          ["x-vercel-ip-country", "x-visitor-country"],
          ["x-vercel-ip-city", "x-visitor-city"],
          ["x-vercel-ip-latitude", "x-visitor-latitude"],
          ["x-vercel-ip-longitude", "x-visitor-longitude"],
        ]) {
          const value = request.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: request.method,
        headers,
        body: event ? await request.arrayBuffer() : undefined,
        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 { relay as GET, relay as POST };
  2. Add the rewrites

    Merge these into your existing vercel.json, above any catch-all rewrite:

    vercel.json
    {
      "rewrites": [
        { "source": "/a/script", "destination": "/api/metricraven?kind=script" },
        { "source": "/a/event", "destination": "/api/metricraven?kind=event" }
      ]
    }
  3. Deploy

    Push or run vercel deploy. Rewrites and functions apply to preview deployments too.

  4. Point your script tag at your own paths

    Replace your MetricRaven tag with this one. src loads the tracker from your domain and data-api sends its events there too.

    Your website's shared layout
    <script defer src="/a/script" data-api="/a/event" data-site-id="YOUR_SITE_ID"></script>

Verify it works

Open your live site. In the browser's Network panel, /a/script loads the tracker and /a/event answers with ok: true. Nothing goes to metricraven.com from the browser.

In Traffic, your own visit should show your real country and city. If every visit appears to come from your server's or host's location, the visitor IP isn't being forwarded.

Notes

  • A rewrite straight to https://metricraven.com/... is not enough: it can't add x-visitor-ip, so every visit would appear to come from Vercel. Keep the function in the middle.
  • Vercel overwrites x-forwarded-for with the visitor's IP and provides x-vercel-ip-* location headers, which the function forwards. Region is left to MetricRaven's own lookup because Vercel sends a code rather than a name.

How the proxy works and which headers it must send: Use your own domain.

Details

  • The proxy forwards only Content-Type, Origin, User-Agent and the visitor's IP as x-visitor-ip. Your site's cookies and auth headers never leave your server.
  • Origin matters: MetricRaven checks it against your site's allowed domains. A missing or wrong origin is refused with domain_not_allowed.
  • MetricRaven allows about 120 events per minute per visitor IP. Without x-visitor-ip, all of your visitors share the proxy's IP, so busy sites lose events as well as locations.
  • A proxy doesn't guarantee that every blocker will allow tracking.