How to · Next.js

LLM Cost Tracking Per User in Next.js, the Clean Pattern

By Ghiles Asmani, founder of Weckr · Published August 15, 2026

Short version: the right attachment point is your route handler or server action, the one place the authenticated session and the model call already coexist. Singleton Weckr client in lib, two line wrap with the session user id and plan, await wk.flush() before returning in serverless handlers, and cost, margin, and caps per user follow. There is an MIT starter with the whole loop wired if you would rather clone than wire.

The singleton, then the handler

// lib/weckr.ts - module level singletons, same as your other clients
import OpenAI from 'openai';
import { Weckr } from '@weckr/sdk';

export const openai = new OpenAI();
export const wk = new Weckr({
  apiKey: process.env.WECKR_API_KEY!,
  plans: { free: 0, pro: 29 },
});
// app/api/ai/summarize/route.ts
import { openai, wk } from '@/lib/weckr';

export async function POST(req: Request) {
  const session = await auth(req);                 // your auth
  if (!session) return new Response('unauthorized', { status: 401 });
  const { text } = await req.json();

  const result = await wk.chat(openai, {
    model: 'gpt-5.4-mini',
    messages: [{ role: 'user', content: prompt(text) }],
    userId: session.user.id,
    feature: 'summarize',
    plan: session.user.plan,
  });

  await wk.flush();                                // serverless: let the log out
  return Response.json({ summary: result.choices[0].message.content });
}

Note this handler is doing double duty: it is also the API key proxy every Next.js AI app needs anyway, per the proxy pattern, so the tracking rides an architecture you already owe yourself. The flush() matters specifically in serverless: the log is fire and forget, and a function that returns instantly can freeze before the POST leaves.

Next.js specifics worth knowing

  • Server actions: identical pattern, wrap the call inside the action where you have the session, flush before returning.
  • Streaming: direct provider streaming works through the wrapper; via the Vercel AI SDK, forward usage from onFinish instead, the exact code in Vercel AI SDK cost tracking, with the include_usage gotcha from the streaming article.
  • Edge routes: keep model calls on Node runtimes (the usual choice for LLM latency anyway) or POST usage straight to the log endpoint from any runtime.
  • Multi tenant apps: a composite identifier gives tenant and seat grain at once, per AI cost per tenant.

Or clone it working

weckr-nextjs-starter is MIT licensed: Next.js, Supabase auth, Stripe billing, an OpenAI endpoint, and Weckr wired through exactly this pattern, auth to model call to margin row. Deploy it, log a call, and open the Users page to see the loop closed before touching your own codebase.

FAQ

How do I track LLM costs per user in a Next.js app?

In the route handler or server action where you call the provider, which is where the session and the call coexist. Wrap the client with Weckr’s two lines, pass the session user id, a feature label, and the user’s plan, and every call logs with cost recomputed server side and margin against the plan. In serverless handlers, await wk.flush() before returning so the fire and forget log survives the function freezing.

Where should the Weckr client live in a Next.js project?

As a module level singleton in a lib file, constructed once with your key and plans map and imported by every route that calls a model. Constructing per request works but wastes the cap check cache; the singleton pattern matches how you already handle your OpenAI client and database connections.

Does this work with streaming responses in Next.js?

Yes, two ways. Calling providers directly, wk.chat supports streaming with usage captured at stream end. Using the Vercel AI SDK abstractions, forward the usage object from the onFinish callback to Weckr’s log endpoint with your user id, the pattern documented in our Vercel AI SDK guide, remembering OpenAI streams need stream_options include_usage set.

Is there a Next.js starter with this already wired?

Yes: weckr-nextjs-starter on GitHub, MIT licensed, with Next.js, Supabase auth, Stripe billing, an OpenAI endpoint, and Weckr tracking cost and margin per user already integrated. Cloning it is the fastest path to seeing the full loop, auth to model call to margin row, working end to end.

What about API routes on the Edge runtime?

The SDK targets Node runtimes; for Edge routes, either move the model call to a Node runtime route (the common pattern anyway for longer LLM calls) or POST the usage to Weckr’s log endpoint directly with fetch, which works from any runtime since it is one HTTPS call with your key.

Keep reading

Two lines into the handler you already have

Your Next.js app already routes AI calls through handlers with the session in scope; the margin layer is two lines inside them. Free for 50,000 requests a month, dashboard preview on the demo, full API detail in the docs.

See the dashboard with real data, no signup needed.

Try the demo →