Installing the Recorder
The recorder observes your API traffic and sends patterns to Stoney. Zero latency — all reporting is async.
Getting Your Token
- Go to Settings → Connections
- Enter your app name and environment
- Click Add app
- Copy the token (shown once)
Next.js
Create middleware.ts in your project root:
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
const STONEY_TOKEN = process.env.STONEY_RECORDER_TOKEN;
export function middleware(request: NextRequest) {
const start = Date.now();
const response = NextResponse.next();
if (STONEY_TOKEN) {
fetch("https://stoneydev.com/api/recorder/ingest", {
method: "POST",
headers: {
"Authorization": `Bearer ${STONEY_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
environment: process.env.NODE_ENV,
observations: [{
method: request.method,
pathPattern: request.nextUrl.pathname,
statusCode: response.status,
durationMs: Date.now() - start,
}],
}),
}).catch(() => {});
}
return response;
}
export const config = { matcher: "/api/:path*" };Express
const STONEY_TOKEN = process.env.STONEY_RECORDER_TOKEN;
app.use((req, res, next) => {
const start = Date.now();
res.on("finish", () => {
if (STONEY_TOKEN) {
fetch("https://stoneydev.com/api/recorder/ingest", {
method: "POST",
headers: {
"Authorization": `Bearer ${STONEY_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
environment: process.env.NODE_ENV || "production",
observations: [{
method: req.method,
pathPattern: req.route?.path || req.path,
statusCode: res.statusCode,
durationMs: Date.now() - start,
}],
}),
}).catch(() => {});
}
});
next();
});Fastify
const STONEY_TOKEN = process.env.STONEY_RECORDER_TOKEN;
fastify.addHook("onResponse", (request, reply, done) => {
if (STONEY_TOKEN) {
fetch("https://stoneydev.com/api/recorder/ingest", {
method: "POST",
headers: {
"Authorization": `Bearer ${STONEY_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
environment: process.env.NODE_ENV || "production",
observations: [{
method: request.method,
pathPattern: request.url.split("?")[0],
statusCode: reply.statusCode,
durationMs: reply.elapsedTime,
}],
}),
}).catch(() => {});
}
done();
});Hono
const STONEY_TOKEN = process.env.STONEY_RECORDER_TOKEN;
app.use("*", async (c, next) => {
const start = Date.now();
await next();
if (STONEY_TOKEN) {
fetch("https://stoneydev.com/api/recorder/ingest", {
method: "POST",
headers: {
"Authorization": `Bearer ${STONEY_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
environment: process.env.NODE_ENV || "production",
observations: [{
method: c.req.method,
pathPattern: new URL(c.req.url).pathname,
statusCode: c.res.status,
durationMs: Date.now() - start,
}],
}),
}).catch(() => {});
}
});Verifying Installation
After adding the middleware:
- Make a few API requests
- Check Settings → Connections
- Routes should appear within 30 seconds
Last updated on