Cloudflare Workers
Integrate vTilt with Cloudflare Workers — Node SDK on the workerd runtime, waitUntil() to flush events before the worker freezes.
Cloudflare Workers run on the workerd runtime, which supports modern fetch-based libraries like @v-tilt/node. The catch: workers freeze the moment your handler returns, so you must call ctx.waitUntil(client.shutdown()) to make sure batched events actually flush.
#1. Install
npm install @v-tilt/node# wrangler.toml
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2025-01-01"
compatibility_flags = ["nodejs_compat"]
[vars]
VTILT_HOST = "https://www.vtilt.com"
# secrets — set via `wrangler secret put VTILT_TRACKER_TOKEN`#2. Module worker
// src/index.ts
import { VTiltNode } from '@v-tilt/node'
interface Env {
VTILT_TRACKER_TOKEN: string
VTILT_HOST: string
}
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
const vtilt = new VTiltNode(env.VTILT_TRACKER_TOKEN, {
host: env.VTILT_HOST,
})
const url = new URL(request.url)
if (url.pathname === '/track' && request.method === 'POST') {
const { userId, event, properties } = await request.json<{
userId: string
event: string
properties: Record<string, unknown>
}>()
vtilt.capture({ distinctId: userId, event, properties })
}
// Crucial: flush before the worker is frozen.
ctx.waitUntil(vtilt.shutdown())
return new Response(JSON.stringify({ ok: true }), {
headers: { 'content-type': 'application/json' },
})
},
}#3. Identify users
If your worker sits in front of an authenticated app, identify on every request so server-side captures merge with the browser session.
const userId = await getUserIdFromToken(request.headers.get('authorization'))
if (userId) {
vtilt.identify({
distinctId: userId,
anonymousId: getAnonCookie(request),
properties: {
/* ... */
},
})
}#4. Scheduled events
Workers can also emit events from cron triggers. Same pattern — flush via ctx.waitUntil.
export default {
async scheduled(
_controller: ScheduledController,
env: Env,
ctx: ExecutionContext,
) {
const vtilt = new VTiltNode(env.VTILT_TRACKER_TOKEN, {
host: env.VTILT_HOST,
})
vtilt.capture({
distinctId: 'system',
event: 'cron_ran',
properties: { job: 'daily-summary' },
})
ctx.waitUntil(vtilt.shutdown())
},
}#5. As a reverse proxy
A common pattern is to proxy vTilt traffic through your own domain so ad blockers can't strip analytics. See Reverse proxy for a worker-based proxy example that forwards /_vt/* to your vTilt origin.
#Next steps
- Reverse proxy — block-resistant ingestion via your own domain.
- Node SDK / Context & shutdown — request-scoped identity.
- Hono integration — same SDK with framework routing.