Next.js route handler
createX3ProxyHandler from @3x-engine/sdk/next/proxy implements the proxy protocol
with the Fetch API only (Request in, Response out). It works in Next.js route handlers (Node and
Edge runtimes) and in any framework that speaks Fetch (Astro, SvelteKit, Remix, Hono, Bun, Deno).
Setup
npm install {{API_ORIGIN}}/v1/sdk/3x-engine-sdk-0.1.0.tgzX3_API_ORIGIN={{API_ORIGIN}}
{{PROXY_KEY_ENV}}=sk_3x_YOUR_PROXY_KEYimport { createX3ProxyHandler } from "@3x-engine/sdk/next/proxy";
export const { GET, POST, OPTIONS } = createX3ProxyHandler({
apiOrigin: process.env.X3_API_ORIGIN!,
proxyKey: process.env.{{PROXY_KEY_ENV}},
});Point the SDK at the path – <X3Analytics host="{{PROXY_PATH}}" …/>, init({ host: "{{PROXY_PATH}}" })
or data-host="{{PROXY_PATH}}".
What the handler does:
- forwards only
/v1/e,/v1/collect,/v1/c/*,/v1/cband/v1/s/*(everything else → 404); - strips
cookieandauthorization, forwardsuser-agent,originand the body; - sets
x-3x-client-ipfromx-forwarded-for/x-real-ip,x-3x-client-countryfromx-vercel-ip-country/cf-ipcountry, andx-3x-proxy-key; - caches scripts (
public, max-age=3600, stale-while-revalidate=86400).
Without proxyKey the handler still forwards, but the API ignores the forwarded IP – visitors behind
the proxy are then merged. Always set the key in production.
If the site has middleware.ts / proxy.ts, exclude the path from its matcher, and do not name the
folder with a leading underscore (private in the App Router).
Verify
curl -s -o /dev/null -w "%{http_code}\n" https://YOUR-SITE{{PROXY_PATH}}/v1/s/x3.js
curl -s -o /dev/null -w "%{http_code}\n" https://YOUR-SITE{{PROXY_PATH}}/v1/c/{{PUBLISHABLE_KEY}}Both must print 200. Then load a page: the network tab shows POST {{PROXY_PATH}}/v1/e → 204.
A 403 on that request with a correct origin means the proxy key is wrong, revoked or belongs to another
project.
Other runtimes
// Hono / Bun / Deno – mount the same handler
import { createX3ProxyHandler } from "@3x-engine/sdk/next/proxy";
const proxy = createX3ProxyHandler({ apiOrigin: process.env.X3_API_ORIGIN!, proxyKey: process.env.X3_PROXY_KEY });
app.all("/n3/*", (c) => {
const method = c.req.method as "GET" | "POST" | "OPTIONS";
return proxy[method] ? proxy[method](c.req.raw) : new Response(null, { status: 405 });
});On Vercel the incoming x-forwarded-for is set by Vercel itself and safe to use. On a plain Node
server behind your own load balancer, make sure the balancer overwrites x-forwarded-for – a client
can otherwise spoof its first entry.