Platforms
handle(request) takes a standard Request and resolves to a Response for tracker requests under /_i/
(change it with prefix), or null for everything else so your app answers. Pass waitUntil where the
platform has it, so recording finishes after the response.
Cloudflare Workers
Section titled “Cloudflare Workers”import { createClient } from '@plaintrace/server'
export default { async fetch(request: Request, env: Env, ctx: ExecutionContext) { const analytics = createClient({ key: env.ANALYTICS_KEY, endpoint: 'https://collect.plaintrace.dev' }) const res = await analytics.handle(request, { waitUntil: (p) => ctx.waitUntil(p) }) if (res) return res return fetch(request) // or your app },}CF-Connecting-IP is trusted by default on Workers. Creating the client per request is fine; create it once at
module level if you prefer.
Next.js middleware
Section titled “Next.js middleware”See the Next.js guide.
import { createClient } from '@plaintrace/server'
const analytics = createClient({ key: Bun.env.ANALYTICS_KEY!, endpoint: 'https://collect.plaintrace.dev' })
Bun.serve({ async fetch(request, server) { // Exposed directly: the socket address is the visitor's. const res = await analytics.handle(request, { ip: server.requestIP(request)?.address }) return res ?? app(request) },})Behind a reverse proxy, drop ip and pass ipHeader (for example 'x-real-ip') to createClient instead:
ip always wins, and the socket address would then be the proxy’s.
import { createClient } from 'npm:@plaintrace/server'
const analytics = createClient({ key: Deno.env.get('ANALYTICS_KEY')!, endpoint: 'https://collect.plaintrace.dev' })
// Exposed directly; behind a reverse proxy use ipHeader on createClient instead of ip.Deno.serve(async (request, info) => (await analytics.handle(request, { ip: info.remoteAddr.hostname })) ?? app(request))Node 24 frameworks built on web Request (Hono, for example) work as above. With a bare Node server, put a
proxy that sets x-real-ip in front and pass ipHeader: 'x-real-ip'; behind no proxy, pass ip yourself.
The script tag
Section titled “The script tag”Point the tracker at your own domain once the proxy runs:
<script async src="/_i/t.js" data-site="<site id>" data-endpoint="/_i"></script>