Serverless & edge¶
Serverless and edge runtimes may freeze or end the process the moment a response is sent, so the regular Node SDK's background flush can't run there. reqly-node/edge sends each request's event right after its response, kept alive by the platform's waitUntil. It uses only web APIs (fetch, WebCrypto, CompressionStream), no node: modules, so it runs on Cloudflare Workers without nodejs_compat.
Wrap any fetch-style handler, (request) => Response, with reqlyFetch:
import { reqlyFetch } from "reqly-node/edge";
async function handle(request, env, ctx) {
return Response.json({ ok: true });
}
export default {
// options may be a function of env, for secrets in bindings
fetch: reqlyFetch(handle, (env) => ({
serviceName: "edge-api",
collectorUrl: env.REQLY_COLLECTOR_URL,
apiKey: env.REQLY_API_KEY,
route: (request) => new URL(request.url).pathname.replace(/\/\d+(?=\/|$)/g, "/:id"),
})),
};
The event is sent with ctx.waitUntil.
// app/api/orders/[id]/route.ts
import { after } from "next/server";
import { reqlyFetch } from "reqly-node/edge";
async function getOrder(request: Request) {
return Response.json({ id: 1 });
}
export const GET = reqlyFetch(getOrder, {
serviceName: "web",
route: "/api/orders/[id]", // recorded as /api/orders/{id}
waitUntil: after,
});
On Vercel the request context's waitUntil is found by itself, so waitUntil: after is only needed elsewhere. [id], [...slug] and [[...slug]] become {id} and {slug}.
import { reqlyFetch } from "reqly-node/edge";
const handler = reqlyFetch((request) => new Response("ok"), {
serviceName: "api",
route: (request) => new URL(request.url).pathname,
});
Deno.serve(handler); // or Bun.serve({ fetch: handler }), or export default handler
Long-running servers keep the send running on their own; no waitUntil needed.
Options¶
The same as the Node SDK's where they apply. Each falls back to its REQLY_* environment variable where the runtime has process.env (Vercel, Netlify, Bun, Deno with --allow-env); on Workers pass them from env.
| Option | Default | Notes |
|---|---|---|
serviceName |
REQLY_SERVICE_NAME |
|
collectorUrl |
REQLY_COLLECTOR_URL |
|
apiKey |
REQLY_API_KEY |
an ingest key, or a project key with the ingest scope |
route |
__unmatched__ |
a template string, or (request, response) => string. Return a template, never the raw path |
release / environment |
REQLY_RELEASE, VERCEL_GIT_COMMIT_SHA, CF_PAGES_COMMIT_SHA, … / REQLY_ENVIRONMENT, VERCEL_ENV |
|
consumerHeader, consumer, consumerSalt, hashConsumer |
as the Node SDK | hashed with WebCrypto HMAC-SHA256: the same ids as the Node and Python SDKs |
sampleRate, traceSlowMs |
1, 500 |
|
waitUntil |
ctx.waitUntil, else Vercel's |
e.g. Next's after, or waitUntil from @vercel/functions |
How it differs from the Node SDK¶
- One send per request. No batching across requests, since there's no "later" to batch for. A send is one attempt with a 3-second timeout; a failure drops that request's event.
- Duration is the time to the response headers; a streamed body may finish later.
- No LLM usage per request.
recordLlmUsageneedsAsyncLocalStorage, which edge runtimes don't all have. Record LLM calls from a Node runtime, or send GenAI spans over OpenTelemetry. - Frameworks with their own adapters (Express, Fastify, Koa, NestJS, Hono on Node) should keep using the Node SDK. Hono on Workers can wrap
app.fetch:export default { fetch: reqlyFetch(app.fetch, …) }.