2026-07-17 · 6 min read
Track your Next.js API callers with one middleware file
Add caller identification and traffic logging to any Next.js API in about five minutes, with a single middleware.ts file and zero added latency.
If your Next.js app exposes API routes — a public API, a webhook receiver, or partner-facing endpoints — you almost certainly have no idea who is actually calling them. Your host's dashboard tells you request counts and status codes at best. It won't tell you that one customer accounts for 80% of your traffic, or that an unauthenticated scraper has been hitting /api/search every few seconds since last Tuesday.
This guide adds caller-level tracking to any Next.js App Router project using a single middleware.ts file and WhoHitsMyAPI's ingest endpoint. No SDK, no new dependency — just a fetch call.
1. Get an API key
Create a free account and generate an API key from the dashboard. Keys are prefixed whma_ and the free plan covers 10,000 tracked requests a month — enough to validate this on a real project before you consider Pro.
Store it as an environment variable:
# .env.local
WHOHITSMYAPI_KEY=whma_your_key_here2. Add the middleware
Create middleware.ts at your project root (next to app/). It intercepts every request matching your API routes, forwards a caller fingerprint to WhoHitsMyAPI, and lets the request continue — the tracking call is fire-and-forget, so it adds no latency to your response.
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
export function middleware(request: NextRequest) {
const started = Date.now();
// Fire-and-forget: don't await, don't block the response
fetch("https://whohitsmyapi.veridux.ai/api/ingest", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.WHOHITSMYAPI_KEY!,
},
body: JSON.stringify({
endpoint: request.nextUrl.pathname,
method: request.method,
ip: request.headers.get("x-forwarded-for") ?? "unknown",
userAgent: request.headers.get("user-agent") ?? "unknown",
// Pass your own caller identity if the request is authenticated —
// e.g. a decoded API key ID, tenant slug, or account email domain.
callerId: request.headers.get("x-api-key") ?? undefined,
latencyMs: Date.now() - started,
}),
}).catch(() => {
// Never let a tracking failure affect the real request
});
return NextResponse.next();
}
export const config = {
matcher: "/api/:path*",
};The matcher config scopes this to /api/* so your pages and static assets aren't tracked — adjust it to whatever prefix your public API actually lives under.
3. Capture the real status code (optional)
Next.js middleware runs before your route handler, so it doesn't know the eventual response status. If you want accurate status codes and latency in your analytics instead of just the request shape, log from inside the route handler itself:
// app/api/search/route.ts
export async function GET(request: Request) {
const started = Date.now();
const result = await runSearch(request);
fetch("https://whohitsmyapi.veridux.ai/api/ingest", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.WHOHITSMYAPI_KEY!,
},
body: JSON.stringify({
endpoint: "/api/search",
method: "GET",
statusCode: result.status,
latencyMs: Date.now() - started,
}),
}).catch(() => {});
return result;
}Both approaches are valid — middleware is less code for broad coverage, per-route logging is more precise. Most teams start with middleware and add per-route logging only for their highest- value endpoints.
4. Read your traffic
Open your dashboard and you'll see requests appear within seconds — grouped by caller, endpoint, method, and status code, with country-level geolocation resolved automatically from the request IP. Sort by request count to find your top callers, or filter by endpoint to check error rates on a route you're about to deprecate.
What this unlocks
- Caller identification — know which customer, partner, or bot accounts for your traffic, not just an aggregate request count.
- Abuse detection — spot a single IP or key making thousands of calls per hour before it shows up as a cloud bill.
- Conversion signal — high- volume free-tier callers are your best upgrade leads. Now you can actually see who they are.
See more patterns like this on the use cases page.
Try it on your own API
Free plan includes 10,000 requests per month. No credit card required.
Get Started Free