Docs

Netlify edge function

Netlify redirects with status 200 cannot add headers, so the proxy runs as an edge function.

Setup

.env
X3_API_ORIGIN={{API_ORIGIN}}
{{PROXY_KEY_ENV}}=sk_3x_YOUR_PROXY_KEY

Set both variables in Site configuration → Environment variables as well (scope: Functions).

netlify/edge-functions/x3-proxy.ts
import type { Config, Context } from "@netlify/edge-functions";

const PREFIX = "{{PROXY_PATH}}";
const ALLOWED = /^\/v1\/(?:e|collect|cb|c\/[^/]+|s\/[A-Za-z0-9@._-]+)$/;

export default async (request: Request, context: Context): Promise<Response> => {
  const url = new URL(request.url);
  const path = url.pathname.slice(PREFIX.length);
  if (!ALLOWED.test(path)) return new Response("not found", { status: 404 });

  const headers = new Headers();
  for (const name of ["user-agent", "origin", "content-type", "accept", "sec-fetch-site", "sec-gpc", "dnt"]) {
    const value = request.headers.get(name);
    if (value) headers.set(name, value);
  }
  headers.set("x-3x-client-ip", context.ip);
  headers.set("x-3x-client-country", context.geo.country?.code ?? "");
  headers.set("x-3x-proxy-key", Netlify.env.get("{{PROXY_KEY_ENV}}") ?? "");

  const upstream = await fetch(new URL(path + url.search, Netlify.env.get("X3_API_ORIGIN")), {
    method: request.method,
    headers,
    body: request.method === "POST" ? await request.arrayBuffer() : undefined,
  });
  const response = new Response(upstream.body, upstream);
  response.headers.delete("set-cookie");
  if (path.startsWith("/v1/s/") && upstream.ok) response.headers.set("cache-control", "public, max-age=3600, stale-while-revalidate=86400");
  return response;
};

export const config: Config = { path: "{{PROXY_PATH}}/*" };

Deploy as usual (netlify deploy --prod or a Git push).

Verify

curl -s -o /dev/null -w "%{http_code}\n" https://YOUR-SITE{{PROXY_PATH}}/v1/s/x3.js

Prints 200; POST {{PROXY_PATH}}/v1/e from a page returns 204. context.ip is the client address as seen by Netlify's edge and cannot be spoofed by the visitor.