Per-user cost attribution for your AI APP To track AI API costs per individual user by attaching a `userId` tag to every LLM call. It presents three methods: using wrapper SDKs like `@voightxyz/openai` with `withTrace`, leveraging the Vercel AI SDK's `experimental_telemetry.metadata`, or manually emitting events for background workers. The key insight is that tagging requests at the boundary allows cost attribution to propagate automatically, enabling developers to identify which users drive their OpenAI or Anthropic bills. You ship your AI feature. It works. A week later your OpenAI bill is $400 and you have no idea which of your users caused which $0.05. This is the single most underrated metric in production LLM apps — cost per end-user — and it's surprisingly easy to instrument if you know what to do. Here are the three approaches I've found work in practice, ranked by setup time. Approach 1: Wrap your provider client 5 minutes Works for Express, Next.js Route Handlers, Fastify — anything that has a single OpenAI or Anthropic client instance. python import OpenAI from 'openai' import { wrapOpenAI, withTrace } from '@voightxyz/openai' const openai = wrapOpenAI new OpenAI , { agent: 'production-chat-api', } app.post '/api/chat', async req, res = { await withTrace async = { const r = await openai.chat.completions.create { model: 'gpt-4o-mini', messages: req.body.messages, } res.json { reply: r.choices 0 .message } }, { routeTag: 'POST /api/chat', tags: { userId: req.user.id, plan: req.user.plan, }, }, } The trick is withTrace { tags: { userId } } at the request boundary. Every LLM call inside the block — direct or nested — inherits those tags automatically via AsyncLocalStorage . You don't have to thread userId through every function. Pros: simplest. Pros: works with both OpenAI and Anthropic the same way. Cons: requires you to use the dedicated wrapper SDKs. Approach 2: OpenTelemetry telemetry metadata Vercel AI SDK If you're on the Vercel AI SDK, experimental telemetry.metadata is the equivalent hook: js import { openai } from '@ai-sdk/openai' import { streamText } from 'ai' export async function POST req: Request { const result = streamText { model: openai 'gpt-4o-mini' , prompt: await req.json .prompt, experimental telemetry: { isEnabled: true, metadata: { userId: session.user.id, plan: session.user.plan, }, }, } return result.toAIStreamResponse } This lifts onto ai.telemetry.metadata.