Pricing & Costs
BothHow the SDK calculates LLM costs locally, how to keep your pricing snapshot fresh, and how SDK costs relate to platform-recomputed costs.
Traccia automatically calculates LLM costs at the moment each span ends, using a pricing table bundled with the SDK. This gives you cost visibility with zero configuration, even without a Traccia account. When you use the Traccia platform, costs are also recomputed server-side using an authoritative, org-aware snapshot.
How Cost Estimation Works
Cost estimation is enabled by default whenever enable_costs=True (the default). For each LLM span the SDK:
- 1Reads
prompt_tokensandcompletion_tokensfrom the LLM response (or counts them via tiktoken for providers that don't return usage). - 2Looks up the model's per-1K-token rates from the active pricing snapshot (see resolution order below).
- 3Computes
cost = (prompt_tokens / 1000 × prompt_rate) + (completion_tokens / 1000 × completion_rate). - 4Writes the result to the span as
llm.cost.usd, along with pricing context attributes (see below).
from traccia import initfrom openai import OpenAI
init() # enable_costs=True by default
client = OpenAI()response = client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "Hello"}])
# The span automatically includes:# llm.cost.usd → 0.000125 (computed from token counts × rates)# llm.token.prompt_tokens → 10# llm.token.completion_tokens → 15# llm.pricing.source → "local_cache"# llm.pricing.generated_at → "2026-04-18T00:00:00Z"# llm.pricing.age_days → 0Pricing Resolution Order
The SDK checks pricing sources in this order, using the first match found:
Programmatic override
Passed directly to init() or start_tracing() via pricing_override={…}. Always takes precedence.
init(pricing_override={…})Environment variable override
Set TRACCIA_PRICING_OVERRIDE_JSON as a JSON string. Persists across restarts without code changes.
TRACCIA_PRICING_OVERRIDE_JSON='{…}'Local cache
Downloaded by traccia pricing refresh and stored at ~/.cache/traccia/pricing.json. Refreshed on demand.
traccia pricing refreshBundled snapshot
Packaged inside the SDK wheel at release time from the same upstream source. Always present as the final fallback.
pip install --upgrade tracciaPer-Span Pricing Attributes
Every LLM span includes these attributes so you (and the platform) can always see exactly what pricing the SDK used at emit time:
| Attribute | Description |
|---|---|
llm.cost.usd | Total cost in USD for this span (prompt + completion). |
llm.pricing.source | Which source was used: bundled | local_cache | env | override. |
llm.pricing.generated_at | ISO 8601 timestamp when the active pricing snapshot was generated. |
llm.pricing.age_days | Integer age of the snapshot in days at the time the span was emitted. |
llm.token.prompt_tokens | Prompt (input) tokens consumed. |
llm.token.completion_tokens | Completion (output) tokens generated. |
llm.token.total_tokens | Total tokens (prompt + completion). |
llm.usage.prompt_tokens | Canonical token attribute written by the SDK processors. |
llm.usage.completion_tokens | Canonical token attribute written by the SDK processors. |
llm.usage.total_tokens | Canonical total token count. |
llm.usage.source | Where token counts came from (provider_usage, tiktoken, mixed). |
Keeping Prices Fresh
The bundled snapshot is generated at SDK release time from an upstream database of 2,500+ models. It is always accurate at the time of release, but model prices change frequently. Between SDK upgrades you can pull the latest pricing without touching your code:
# Pull the latest from the Traccia platform (or upstream if platform unreachable)traccia pricing refresh
# Check the current snapshot age and sourcetraccia pricing status
# Force upstream (no account needed)traccia pricing refresh --source upstreamSnapshot > 7 days old
SDK logs an INFO reminder to refresh.
Snapshot > 30 days old
SDK logs a WARNING with the exact refresh command.
Add to CI or agent startup
traccia pricing refresh as part of your CI pipeline or container entrypoint to ensure every deployment starts with a current snapshot. The command exits immediately with no download if prices have not changed (HTTP 304).Overriding Pricing
Use overrides for fine-tuned models, custom API pricing, or internal cost allocation rates. Overrides always win over any other source.
Programmatic (per-process)
Passed directly to init(). Affects only the current Python process.
import traccia
traccia.init( pricing_override={ "gpt-4o": {"prompt": 0.005, "completion": 0.015}, "my-fine-tuned-gpt4": {"prompt": 0.008, "completion": 0.024}, })Environment variable (persistent)
Persists across restarts without code changes. Set in your .env or deployment environment.
export TRACCIA_PRICING_OVERRIDE_JSON='{"gpt-4o": {"prompt": 0.005, "completion": 0.015}}'Deprecation: AGENT_DASHBOARD_PRICING_JSON
AGENT_DASHBOARD_PRICING_JSON environment variable is still accepted as a back-compat alias but will be removed in a future minor version. Rename it to TRACCIA_PRICING_OVERRIDE_JSON in your environment.Override JSON schema
{ "<model-name>": { "prompt": 0.005, "completion": 0.015, "cache_write": 0.001, "cached_prompt": 0.0005 }}All rates are USD per 1,000 tokens. cache_write and cached_prompt are optional — for models with prompt-caching pricing (e.g. Claude 3.5 Sonnet).
Non-LLM Spans
The cost processor only annotates spans that look like LLM calls. If a span has span.type set to anything other than llm (case-insensitive), cost attributes are skipped — even when token counts are present. Leave span.type unset or set it to llm on LLM spans.
# Tool span — no llm.cost.usd addedwith span("search_web", {"span.type": "tool"}) as s: results = search(query)
# LLM span — cost calculated normallywith span("llm.call", {"span.type": "llm", "llm.model": "gpt-4o"}) as s: response = client.chat.completions.create(...)Disabling Cost Calculation
Cost estimation is enabled by default. To disable it (for example, to reduce span attribute size or when you rely entirely on platform-side costs):
# Programmatictraccia.init(enable_costs=False)
# Environment variable# TRACCIA_ENABLE_COSTS=false
# traccia.toml# [instrumentation]# enable_costs = falsePlatform costs still work
llm.usage.prompt_tokens and llm.usage.completion_tokens, the platform can still compute platform_cost_usd.SDK Costs vs Platform Costs
The SDK's llm.cost.usd and the platform's platform_cost_usd are computed independently and may differ slightly. This is by design.
| Aspect | SDK (llm.cost.usd) | Platform (platform_cost_usd) |
|---|---|---|
| When computed | At span end, in your process | Asynchronously after ingestion (~15s) |
| Pricing source | Local snapshot (bundled / cache / override) | Platform snapshot + org overrides |
| Org overrides applied | No | Yes |
| Mutable | Never changed after emit | Updated on recomputation |
| Visible in UI | Secondary — shown in span detail panel | Primary — shown everywhere |
See Platform Costs for a detailed explanation of divergence scenarios and how to resolve them.
See Also
© 2026 Traccia.