# Proxy with Vercel

> Use vercel.json rewrites and a Vercel Function to serve MetricRaven from your domain.

Source: https://metricraven.com/docs/proxy-vercel  
Markdown: https://metricraven.com/docs/proxy-vercel.md  
Section: Proxy

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](https://metricraven.com/docs/proxy-nextjs) instead.

   ```javascript title="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:

   ```json title="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.

   ```html title="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](https://metricraven.com/docs/proxy).

## 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.
