Skip to content
telemetry.dev
Esc
↑↓navigate↵open⌘Jpreview
On this page

Cost calculation

Learn how telemetry.dev calculates model cost from token usage and model prices.

telemetry.dev sets each span’s cost when the span is ingested:

  1. If the span carries a valid client cost, that value is stored as sent.
  2. Otherwise, the server multiplies the span’s token counts by the model’s prices from a pricing snapshot.
  3. If neither is possible, the cost is null, which means unknown. A known cost of zero is stored as 0.

Costs are in US dollars.

Server calculation

Snapshot prices are US dollars per 1,000,000 tokens. The server splits the span’s input into three parts and prices each part with its own rate:

Token part Tokens Price field If the price is missing
Uncached input Input minus cache read minus cache creation input —
Cache read Cache-read input tokens cachedInput input
Cache creation Cache-creation input tokens cacheWrite input
Output Output tokens output —
uncached = max(0, input - cacheRead - cacheCreation)

cost = ( uncached      * price.input
       + cacheRead     * (price.cachedInput ?? price.input)
       + cacheCreation * (price.cacheWrite  ?? price.input)
       + output        * price.output
       ) / 1,000,000

input is the total input, including cache reads and cache creation. output includes reasoning tokens, so reasoning has no separate charge. For which attributes supply each count, see Token usage.

Worked example

This span used 12,000 input tokens, of which 8,000 were read from cache and 1,000 were written to cache, and 1,500 output tokens:

{
  "gen_ai.provider.name": "anthropic",
  "gen_ai.request.model": "claude-sonnet-4-5",
  "gen_ai.usage.input_tokens": 12000,
  "gen_ai.usage.cache_read.input_tokens": 8000,
  "gen_ai.usage.cache_creation.input_tokens": 1000,
  "gen_ai.usage.output_tokens": 1500
}

The prices below are illustrative. They match the anthropic:claude-sonnet-4-5 entry in the snapshot of 2026-09-24, but each new snapshot can change them.

Where the cost of this span comes from

Token partTokensPrice per 1MCost
Uncached input3,000$3.00$0.009
Cache read8,000$0.30$0.0024
Cache creation1,000$3.75$0.00375
Output1,500$15.00$0.0225
Total13,500$0.03765
Uncached input is 12,000 − 8,000 − 1,000 = 3,000 tokens. Cache reads are most of the tokens but a small part of the cost; output is a small part of the tokens but most of the cost.

The stored cost is 0.03765. Adding reasoning tokens to this span would not change it, because they are already counted in the 1,500 output tokens.

Rounding and precision

The server works with exact decimal values of the prices, not floating-point arithmetic. It rounds the final cost once, to the nearest 0.00000001 dollars (eight decimal places), and drops trailing zeros. For example, 7 input tokens at $3.00 per million is stored as 0.000021.

A stored cost can have at most ten digits before the decimal point. A calculated cost above $9,999,999,999.99999999 is null.

Client cost

A client cost replaces the server calculation. Use it for a custom or private model, for negotiated prices, or when the snapshot does not know your model. It does not need a model or token counts.

The ingest API checks these attributes in order and uses the first valid one:

  1. gen_ai.usage.cost
  2. ai.usage.cost
  3. td.cost_usd
  4. telemetry.dev.cost_usd

A valid client cost is one of:

  • A finite, nonnegative number. The server rounds it to eight decimal places.
  • A string of digits with an optional decimal part of one to eight digits, such as "0.5" or "12.00000001". Strings with a sign, an exponent, or more than eight decimal places are invalid.

Either way, the value can have at most ten digits before the decimal point. An invalid value is skipped, and the next attribute in the list is tried.

The first-party SDKs send costUsd (TypeScript) and cost_usd (Python) as gen_ai.usage.cost.

When cost is null

The server stores a null cost, and adds nothing to the trace total, when there is no valid client cost and any of these is true:

  • The span has no model attribute.
  • No snapshot entry matches the provider and model; see Model matching.
  • The span has no token counts at all.
  • The span has an input count, and cache read plus cache creation is larger than it. The ingest API also records the diagnostic inconsistent_usage_counts.
  • The model has context tiers and the span reports no input count of its own.
  • The modality counts contradict the aggregate counts; see Modality pricing.
  • A one-hour cache-creation count or a compaction count is larger than the total it is part of; see Provider-specific adjustments.
  • The result is larger than $9,999,999,999.99999999.

If a model is missing from the snapshot or priced wrong for you, send a client cost.

Modality pricing

Some providers price image and audio tokens differently from text. When a span carries modality usage attributes, the server prices the reported image and audio parts with their own rates, and the rest of each aggregate at the text rate:

Part Price field If the price is missing
Image input, uncached imageInput input
Audio input, uncached audioInput input
Image cache read imageCachedInput cachedInput, then input
Audio cache read audioCachedInput cachedInput, then input
Image output imageOutput output
Audio output audioOutput output
Text and any remainder input, cachedInput, output As in the main table

A modality’s uncached input is its input count minus its own cache-read count. Two cases keep a modality’s uncached input at the base input rate instead:

  • The span has a cache-read count above zero but no cache-read count for that modality. Send the modality’s cache-read count, even 0, to avoid this.
  • The span has any cache creation. The server cannot tell which modality the cache writes belong to, so it does not split them.

Reported image and audio cache reads still use their own cache-read rates in both cases, and cache creation still uses cacheWrite.

When a span has no aggregate count for a kind, the server uses the sum of its modality counts for that kind.

The cost is null when the modality counts contradict the aggregates:

  • Image plus audio uncached input, at their modality rates, is larger than the total uncached input.
  • The modality cache reads add up to more than the cache-read total, or a modality’s cache read is larger than its own input.
  • Image plus audio output is larger than the output total.

These are token-cost estimates. Snapshot entries without image or audio rates price every modality at the text rate. The calculation does not include per-image generation fees, service-tier surcharges, or other charges that a provider bills outside token counts.

Context tiers

Some models charge more for every token once a request’s input is larger than a threshold. For these models, the total input count, including cache reads and cache creation, selects the rates for the whole request. The server does not charge only the tokens above the threshold at the higher rate.

A tiered model has a null cost when the span reports no input count of its own, because the server cannot pick a tier. An input attribute or modality input counts are enough, and so is the total on an embeddings or rerank span. An input that the ingest API filled in from cache counts, or from the total on another kind of span, is not.

Provider-specific adjustments

These adjustments come from Claude Platform and Claude Code telemetry:

Adjustment Applies when Effect
One-hour cache writes The span has anthropic.usage.cache_creation.ephemeral_1h_input_tokens That part of cache creation is priced at cacheWrite1h, falling back to cacheWrite and then input. The rest of cache creation uses cacheWrite.
Fast mode A Claude Code claude_code.llm_request span has speed set to fast, and the snapshot entry has a fast-mode multiplier Every rate is multiplied by the entry’s multiplier.
Compaction An Anthropic SDK request span has anthropic.usage.compaction.input_tokens or anthropic.usage.compaction.output_tokens The compaction tokens are added to the span’s input and output, and priced as a separate request with all input uncached. They do not change the main request’s context tier.

Pricing snapshot

The server reads prices from a pricing snapshot that telemetry.dev updates from the four catalogs below. It does not call any catalog while it ingests a span, so a price change reaches telemetry.dev with the next snapshot, not immediately. The set of priced models can change between snapshots.

Source Role
models.dev Primary prices for direct and hosted providers
LiteLLM Fills provider and model entries that models.dev lacks. For entries models.dev has, fills only image and audio rates, one-hour cache-write rates, and fast-mode multipliers.
Vercel AI Gateway Prices for Vercel AI Gateway routes only
OpenRouter Prices for OpenRouter routes only

Gateway routes are priced only from their own catalog. A Vercel AI Gateway or OpenRouter route missing from that catalog has no price, even if another provider prices the same model.

Model matching

Before the lookup, the server trims and lowercases the model, and removes these Google Vertex prefixes:

  • projects/<project>/locations/<location>/publishers/google/models/
  • publishers/google/models/
  • models/

It then trims and lowercases the provider and maps these names:

Received provider Lookup provider
gcp.vertex_ai, vertex, vertex_ai google-vertex
gcp google
aws, bedrock, bedrock_converse amazon-bedrock
azure.ai.inference azure_ai
gateway, vercel_ai_gateway, vercel ai gateway vercel
fireworks_ai fireworks-ai
ibm.watsonx.ai watsonx
mistral_ai mistral
together_ai togetherai
x_ai xai
Any other name that contains . The part before the first ., then the mappings above

The lookup tries these model forms, in order:

  1. The model as received.
  2. The model without a version or date suffix: a - or @ followed by YYYY-MM-DD, YYYYMMDD, vN, latest, or three digits at the end.
  3. The Anthropic form, which changes a leading claude-N-M- to claude-N.M-.
  4. The Anthropic form without a version or date suffix.

For example, claude-3-5-sonnet-20241022 is tried as claude-3-5-sonnet-20241022, claude-3-5-sonnet, claude-3.5-sonnet-20241022, and claude-3.5-sonnet.

The server first looks up provider:model for each form. If none matches, or the span has no provider, it looks up each form without a provider. That lookup uses the entry from the first provider in this order that prices the model: openai, anthropic, google, google-vertex, xai, deepseek, mistral, meta, meta-llama, cohere, groq, amazon-bedrock, azure, then all other providers in alphabetical order.

The vercel and openrouter providers skip the lookup without a provider, because gateway routes are priced only from their own catalog.

The snapshot also has an entry for each undated model family, such as gpt-4o, that points to the family’s -latest entry or, without one, its newest dated version, unless the catalog already lists the family name.

Trace totals

A trace’s cost is the sum of its spans’ costs. It stays null until at least one span has a cost, so a trace with no priced spans shows no cost rather than $0.

For integrations that report the same usage on more than one span, such as OpenClaw, Eve, and Claude Platform, the server counts that usage once in trace totals.

Last updated on October 18, 2026

Was this page helpful?