Sign up

Proxy

Proxy with Astro

On this page

An on-demand Astro endpoint relays the script and events. It needs a server adapter.

Set it up

  1. Make sure your project has an adapter

    Server endpoints run only with an adapter such as @astrojs/node, @astrojs/vercel, @astrojs/netlify or @astrojs/cloudflare. Add one with npx astro add node (or your host's name). Fully static sites: use your host's recipe instead (see the notes).

  2. Add the endpoint

    src/pages/a/[kind].ts
    // src/pages/a/[kind].ts · needs an Astro adapter (Node, Vercel, Netlify or Cloudflare)
    import type { APIRoute } from "astro";
    
    export const prerender = false;
    
    export const ALL: APIRoute = async ({ params, request, clientAddress }) => {
      const script = params.kind === "script" && request.method === "GET";
      const event = params.kind === "event" && request.method === "POST";
      if (!script && !event) return new Response("Not found", { status: 404 });
      const headers = new Headers({ "x-visitor-ip": clientAddress });
      for (const name of ["content-type", "origin", "user-agent"]) {
        const value = request.headers.get(name);
        if (value) headers.set(name, 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",
        },
      });
    };

    clientAddress is the visitor IP as your adapter reports it. prerender = false keeps this one route on demand even when the rest of the site is static.

  3. Update the tag in your base layout

    Astro doesn't bundle a script tag that has attributes besides src, so the tag works as is. Adding is:inline makes that explicit.

  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

  • Static Astro builds have no server. Use the Vercel, Netlify or Cloudflare Workers recipe for your host.
  • With the Node adapter behind a load balancer, check that clientAddress is the visitor and not the balancer.

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.