Skip to main content
createFetchMiddleware returns a function with this shape:
That is exactly Astro’s middleware signature, so on Astro you export it directly. Every other framework has its own shape and needs two or three lines to bridge. They are all below.
Do not export const handle = createFetchMiddleware(beacon) on SvelteKit, or use it as a Nitro handler on Nuxt. Those frameworks call middleware differently and the export will silently never run.

Install

.env
No VITE_ or PUBLIC_ prefix. Those are inlined into the client bundle, which publishes the key.
Create the beacon once and import it where you need it:
src/lib/beacon.ts

Wiring it up

Verify any of them:

Nuxt

Nuxt is the awkward one. Nitro middleware runs before the route handler and cannot wrap its response, so createFetchMiddleware does not fit. Serving twins and reporting hits still work; advertising the twin on HTML responses has to be done by hand.
server/middleware/beacon.ts
The Vary: Accept line is not optional. Without it a cache can hand the HTML copy to a client that asked for Markdown, or the reverse.

Serverless runtimes

On Workers, Netlify Edge and similar, pass the platform’s waiting context so a pending report is not killed when the response returns. The snippets above already do:
Without it the report is cancelled mid-flight and the hit is simply lost, with no error anywhere.

Options

endpoint accepts a bare origin; the ingest path is appended for you. See self-hosting to run your own, and the SDK reference for every option.