What Laminar prices
Providers do not bill every token at the same rate, so Laminar does not either. Each LLM span carries the token counts the provider reported, priced per kind:
Two adjustments to the rate itself also happen automatically. A request that crosses a model’s long-context threshold is priced at the above-threshold rate for the whole call, the way
gpt-5.6-sol doubles its input rate past 272k tokens. And a call made on a cheaper or premium service tier, such as OpenAI’s flex or priority, is priced at that tier’s rate rather than the standard one.
gen_ai.usage.input_tokens is the total input count, cached tokens included. Laminar subtracts the cache read and write counts from it to get the tokens billed at the regular input rate, so if you are instrumenting by hand, do not add cached tokens on top of the input total.spans and traces: input_tokens, output_tokens, cache_read_input_tokens, cache_creation_input_tokens, reasoning_tokens, input_cost, output_cost, and total_cost. So “how much of last week’s bill was reasoning tokens” is a query, not an estimate.
Break spend down by user, session, or customer
Costs roll up from each LLM span to the span that contains it and on to the trace, so a run that fans out across tools, subagents, and providers still resolves to one number:- Model and provider, including a mix of providers in one run
- Agent or workflow, through span and trace names
- Session, a full conversation or multi-step run
- User, through the user ID on the trace
- Metadata and tags, so you can slice by environment, customer, feature, or experiment
- TypeScript
- Python
Which models and providers are priced
Laminar prices effectively every model from every major provider, and keeps up as providers change their rates. Prices are resolved on the Laminar server rather than in the SDK, so a model that shipped this morning is priced correctly with the SDK version you already have. Pricing is per span, so a run that mixes providers needs no special handling: each call is priced against its own model and provider, and the trace total is their sum. A self-hosted Laminar prices spans from the same table as the managed cloud, with one caveat: your deployment refreshes it over the network at startup, so an air-gapped install has no built-in prices and needs custom ones. You supply a price yourself only when there is no public one to look up, such as a private, self-hosted, or fine-tuned model, or when your rate differs from list price. Define it once per project under Settings > Model costs, see Custom model costs. The alternative, for cases where you already compute cost yourself, is to set it directly on the span, covered in Instrument calls Laminar does not trace automatically.How Laminar calculates cost
At ingestion, Laminar resolves a price for each LLM span in this order:- Cost attributes on the span. A non-zero
gen_ai.usage.input_cost,output_cost, orcostis taken as the answer and no price table is consulted. - Your project’s custom prices, matched exactly on model and provider.
- The built-in price table, looked up from the model and provider on the span.
gen_ai.response.model, falling back to gen_ai.request.model. Either one is enough, and the response model takes priority because it is the model the provider actually billed you for. Without a model name there is nothing to look up, cost stays at zero, and that is the most common reason a span shows no price.
The provider, from gen_ai.system, narrows the lookup rather than gating it: Laminar tries the provider and model together first, then the model on its own. It matters for models the table lists only under a provider prefix, such as Azure deployments or Gemini, and not at all for OpenAI and Anthropic models, whose names match on their own.
The built-in table also matches forgivingly. Case is ignored, a trailing date snapshot is stripped so gpt-5-mini-2026-04-01 resolves to gpt-5-mini pricing, and a provider/model string is understood. Custom prices are the opposite: they match exactly, so a date suffix on the span that is missing from your entry means no match.
Prices apply at ingestion, so changing a rate does not re-cost spans you have already recorded.
Instrument calls Laminar does not trace automatically
Auto-instrumentation covers the providers and frameworks on the integrations list. Create LLM spans by hand for:- Self-hosted or fine-tuned models behind your own endpoint
- Providers Laminar does not instrument yet
- Direct HTTP calls to an LLM API
- Custom inference servers
What the span needs
Create the span with span typeLLM. Without it the span renders as a generic operation, stays out of transcript view, and is skipped by the cost rollup. Then set:
Cache and reasoning token counts have no SDK constants. Set them as raw attribute keys from the LLM attributes reference if your provider reports them and you want them priced at their own rates.
Provider identifiers
If you are hand-instrumenting a provider Laminar knows, use the identifier the price table is keyed by. These are the common ones, with a model string that resolves against each:
For anything else, including your own endpoint, use whatever identifier you like and give it a price under Settings > Model costs, or set explicit cost attributes on the span.
Example
- TypeScript
- Python
Without the SDK
If you ship OTLP directly to Laminar, set the same fields as raw attribute keys on a span you mark asLLM:
- TypeScript
- Python
Where costs show up
- On trace details, as the sum of every LLM call in the run. See Viewing traces.
- On individual LLM spans, as the cost of that call.
- On dashboards, aggregated by provider, model, or any dimension you set. See Dashboards.
- In the SQL editor, for reporting across traces.
Find wasted spend
Cost tracking tells you what you spent. To find what you wasted, use Signals: plain-language instructions that read whole agent runs and flag the patterns that quietly drive cost, like a tool call retried until the agent gives up. Because a Signal sees the full run rather than isolated token counts, it catches waste that a per-call number cannot show. Signals are also how you hear about it without watching a dashboard. Every Signal comes with an alert that fires on its events, in-app, by email, or into Slack.FAQ
Why is cost showing as zero on my spans? Cost needs a model name and token counts. Missing either leaves cost at zero. A model string the price table does not recognize has the same effect. Can I see cost per user, per session, or per customer? Yes. Set a user ID, session ID, or metadata on the trace and cost aggregates by any of them. Which models and providers are supported? Effectively every model from every major provider, with pricing kept current. Private, self-hosted, and fine-tuned models are priced through custom model costs. Are cached and reasoning tokens counted? Yes, wherever the provider reports them. Both are recorded as their own token counts and priced at their own rates rather than as ordinary input and output. Can I override the calculated cost? Yes. Cost attributes on a span take precedence over every price table, including your own custom prices. Can Laminar cap or block my spending? No. Enforcing a hard limit means refusing a request while it is in flight, which requires sitting in the request path, and Laminar reads your traces rather than proxying your calls. It records what you spent and can flag expensive runs through Signals.Troubleshooting
What’s next
Custom model costs
Set your own prices for private, fine-tuned, or negotiated-rate models.
LLM attributes reference
Every attribute key Laminar reads off an LLM span, including the token and cost keys.
Signals
Catch wasteful and failing runs across your whole trace history.
SQL editor
Query cost across traces for per-customer and per-feature reporting.