So you've integrated the OpenAI API into your Next.js app. Your users love it. But then you get the bill, and you have no idea who's costing you what. A single "power user" could be driving 90% of your costs, and you'd be flying blind.
Let's fix that. Tracking per-user costs isn't just a nice-to-have, it's essential for any application that exposes an LLM to end-users.
The Problem: The Un-instrumented API Call
Your code might look something like this. You have an API route in Next.js that calls OpenAI.
// pages/api/generate.ts
import OpenAI from 'openai';
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export default async function handler(req, res) {
const completion = await openai.chat.completions.create({
messages: [{ role: 'user', content: 'Say this is a test' }],
model: 'gpt-4o',
});
res.status(200).json({ result: completion.choices[0].message.content });
}
This works, but it's a black box. You know a call was made, but you don't know who made it.
The Solution: Attribute Every Call
To fix this, you need to attribute every single API call to a user. This means passing a unique user identifier with every request.
First, protect your API route to make sure you have a user session. Then, wrap your OpenAI calls in a helper function that logs the cost.
// lib/openai.ts
import OpenAI from 'openai';
import { getCostForModel, saveUsageToDatabase } from './billing'; // Fictional helpers
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export async function createChatCompletion(userId: string, options: any) {
const completion = await openai.chat.completions.create(options);
const promptTokens = completion.usage?.prompt_tokens ?? 0;
const completionTokens = completion.usage?.completion_tokens ?? 0;
// Calculate cost based on model (you have to maintain these prices)
const cost = getCostForModel(options.model, promptTokens, completionTokens);
// Save to your database
await saveUsageToDatabase({
userId,
model: options.model,
promptTokens,
completionTokens,
cost,
});
return completion;
}
You'd need a database table to store this, maybe in Supabase:
CREATE TABLE llm_usage (
id bigserial primary key,
created_at timestamp with time zone default now(),
user_id text not null,
model text not null,
prompt_tokens integer not null,
completion_tokens integer not null,
cost numeric(10, 6) not null
);
The Shortcut: Don't Build It Yourself
As you can see, this is a lot of boilerplate. You need to maintain pricing for different models, build a robust logging system, and create a dashboard to view the data.
This is a problem I ran into, so I built LLMeter (llmeter.org). It's an open-source, AGPL-licensed dashboard you can self-host. It gives you a simple SDK to wrap your LLM calls and automatically handles the cost calculation, logging, and dashboarding for multiple providers (OpenAI, Anthropic, Mistral, etc.).
It turns the code above into something much simpler and gives you a production-ready dashboard out of the box.
Whether you build it yourself or use a tool, the takeaway is the same: if you're not tracking LLM costs on a per-user basis, you're driving with your eyes closed. Don't wait for the surprise bill to learn that lesson.
Top comments (0)