How-to · Vercel AI SDK

How to Track AI Costs Per User with the Vercel AI SDK

By Ghiles Asmani, founder of Weckr

The Vercel AI SDK made calling a model a one-liner. generateText, streamText, swap openai for anthropic, ship. What it did not make easy is the question you will ask the first time your bill looks wrong: which of my users generated that cost?

The SDK hands you token usage on every call. It does not attribute it to a user, turn it into dollars, or tell you who is unprofitable. This guide covers how to get usage out of generateText and streamText (including the streaming gotcha most people miss), attribute it to a userId, and track real cost and margin per user.

Cost per user, streamed from the AI SDKstreamText()$29 plan priceuser A$4user B$11user C$38

What the Vercel AI SDK gives you, and what it does not

Every core call in the AI SDK returns a usage object with the token counts for that request. That is the raw material for cost. What it is missing is everything that turns tokens into a business number: no user dimension, no dollar conversion, no per-feature breakdown, and no idea what each customer pays you. The SDK is a great client. It is not a cost or margin tool, and it does not pretend to be.

So the per-user layer lives on your side of the wire, built from the usage the SDK already gives you. The good news is that the usage is right there on every call. You just have to catch it and tag it.

Get token usage from generateText and streamText

For a normal (non-streamed) call, the usage is on the result. Await the call and read it:

import { generateText } from 'ai'
import { openai } from '@ai-sdk/openai'

const { text, usage } = await generateText({
  model: openai('gpt-4o-mini'),
  messages,
})

// usage: { inputTokens, outputTokens, totalTokens }
// (older AI SDK versions call these promptTokens / completionTokens)

Streaming is where people get it wrong, and it matters because streaming is the default for chat UIs. A streamed response has no final token counts until it finishes, so reading usage too early misses every output token. The SDK solves this with the onFinish callback, which fires once the stream completes with the full usage:

import { streamText } from 'ai'
import { openai } from '@ai-sdk/openai'

const result = streamText({
  model: openai('gpt-4o-mini'),
  messages,
  onFinish: ({ usage }) => {
    // this is the ONLY reliable place to record a streamed call's cost
    recordUsage(usage)
  },
})

return result.toDataStreamResponse()

If you take one thing from this article: for streaming, record cost in onFinish, never before. This one gap is why so many teams think their streaming features are cheaper than they are. There is a whole deeper problem here covered in how to track AI costs per user.

Attribute the cost to a user

Usage on its own is an anonymous number. To make it useful, attach the user you already have in context and turn tokens into dollars. Grab the current rate from the provider pricing page and compute:

const PRICES = {
  'gpt-4o-mini': { in: 0.15, out: 0.60 },   // USD per 1M tokens
  'gpt-4o':      { in: 2.5,  out: 10 },
}

function costUsd(model, inputTokens, outputTokens) {
  const p = PRICES[model]
  return (inputTokens * p.in + outputTokens * p.out) / 1_000_000
}

// inside onFinish (or after generateText):
await db.aiUsage.insert({
  userId: session.user.id,       // you have this. The SDK does not.
  feature: 'chat',
  model: 'gpt-4o-mini',
  inputTokens: usage.inputTokens,
  outputTokens: usage.outputTokens,
  costUsd: costUsd('gpt-4o-mini', usage.inputTokens, usage.outputTokens),
  createdAt: new Date(),
})

Do that on every call and you can finally answer the real question with a group-by: sum costUsd per userId for the month, sort descending, and the top of that list is where your margin is going.

Why the do-it-yourself version quietly rots

The snippet above works for a week. Then reality sets in. Providers reprice every few months and your hardcoded table goes stale silently, so your reported cost drifts from your real bill. You add an anthropic model for one feature and a google model for another, and now you are maintaining three pricing tables with three different token accounting rules. Then you want margin per user, not just cost, so you join against subscriptions, prorate mid-month plan changes, and spend a Friday debugging why an upgraded customer shows the wrong revenue. This is the point where most teams give up and go back to staring at the account total.

Track per-user cost with Weckr

Weckr does that layer for you. Because the AI SDK abstracts the raw provider client away, the clean integration is to forward the usage event you already have in onFinish, tagged with your user and plan. Weckr recomputes the cost server side from current pricing (so it never drifts), stores it per user and per feature, and figures margin against the plan:

const result = streamText({
  model: openai('gpt-4o-mini'),
  messages,
  onFinish: async ({ usage }) => {
    await fetch('https://useweckr.com/api/v1/log', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
        'x-api-key': process.env.WECKR_API_KEY,
      },
      body: JSON.stringify({
        userId: session.user.id,
        feature: 'chat',
        model: 'gpt-4o-mini',
        provider: 'openai',
        inputTokens: usage.inputTokens,
        outputTokens: usage.outputTokens,
        planName: user.plan,
        planRevenueUsd: PLAN_PRICES[user.plan],
      }),
    })
  },
})

If instead you call a provider client directly anywhere in your app (not through the AI SDK model abstraction), you can wrap that call in two lines with wk.chat(openai, ...) and skip the manual log entirely. Either way you get cost and margin per user and per feature, model and pricing recommendations, and per-user spending caps that stop a heavy user from running your bill past what they pay. See it on seeded data, no signup, at useweckr.com/demo, and model your plan against real costs with the break-even calculator.

FAQ

Does the Vercel AI SDK track cost per user?

No. The Vercel AI SDK gives you a usage object with token counts on every call (through the result of generateText, or the onFinish callback of streamText), but it does not attribute that cost to your end users, convert it to dollars, or compare it to what each user pays. Per-user cost and margin are on you, which is what this guide covers.

How do I get token usage from streamText in the Vercel AI SDK?

Use the onFinish callback. A streamed response does not have final token counts until it finishes, so streamText exposes usage in onFinish({ usage }), which fires once the stream completes. That is the single place to record cost for a streaming call. Trying to read usage before the stream ends will miss the output tokens.

How do I calculate the dollar cost of a Vercel AI SDK call?

Take the input and output token counts from the usage object and multiply by the current per-million-token price for the model you called. For gpt-4o-mini that is about $0.15 per million input and $0.60 per million output as of 2026. The formula is (inputTokens * inputPrice + outputTokens * outputPrice) / 1,000,000. Recompute from live pricing rather than hardcoding, because providers reprice often.

How do I attribute AI SDK cost to a specific user?

You already have the user id in your request context. Log it next to the usage token counts on every call, either in your own database or by forwarding the event to a service like Weckr. The key is doing it on every call with the user attached, not just reading an account-level total after the fact.

Can I track cost across multiple providers with the Vercel AI SDK?

Yes, and you will need to. The AI SDK makes it easy to mix openai, anthropic, and google models, but each has different token accounting and prices. To compare cost per user across them you have to normalize token counts and apply per-provider pricing, or use a tool that already does that so the numbers line up in one dashboard.

Ship the feature, keep the margin

The Vercel AI SDK removed the friction of calling a model. The cost of that is how easy it is to ship an AI feature without ever seeing what it does to your unit economics. Catch the usage on every call, attribute it to a user, and you turn an anonymous monthly bill into a decision about who to price up, cap, or celebrate. This is one step in the complete guide to AI cost and margin management. See your own per-user numbers at useweckr.com/demo.

See the dashboard with real data, no signup needed.

Try the demo →