Pricing & Costs

Both

How 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:

  1. 1Reads prompt_tokens and completion_tokens from the LLM response (or counts them via tiktoken for providers that don't return usage).
  2. 2Looks up the model's per-1K-token rates from the active pricing snapshot (see resolution order below).
  3. 3Computes cost = (prompt_tokens / 1000 × prompt_rate) + (completion_tokens / 1000 × completion_rate).
  4. 4Writes the result to the span as llm.cost.usd, along with pricing context attributes (see below).
example.py
python
from traccia import init
from 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 → 0

Pricing Resolution Order

The SDK checks pricing sources in this order, using the first match found:

1

Programmatic override

Passed directly to init() or start_tracing() via pricing_override={…}. Always takes precedence.

init(pricing_override={…})
2

Environment variable override

Set TRACCIA_PRICING_OVERRIDE_JSON as a JSON string. Persists across restarts without code changes.

TRACCIA_PRICING_OVERRIDE_JSON='{…}'
3

Local cache

Downloaded by traccia pricing refresh and stored at ~/.cache/traccia/pricing.json. Refreshed on demand.

traccia pricing refresh
4

Bundled snapshot

Packaged inside the SDK wheel at release time from the same upstream source. Always present as the final fallback.

pip install --upgrade traccia

Per-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:

AttributeDescription
llm.cost.usdTotal cost in USD for this span (prompt + completion).
llm.pricing.sourceWhich source was used: bundled | local_cache | env | override.
llm.pricing.generated_atISO 8601 timestamp when the active pricing snapshot was generated.
llm.pricing.age_daysInteger age of the snapshot in days at the time the span was emitted.
llm.token.prompt_tokensPrompt (input) tokens consumed.
llm.token.completion_tokensCompletion (output) tokens generated.
llm.token.total_tokensTotal tokens (prompt + completion).
llm.usage.prompt_tokensCanonical token attribute written by the SDK processors.
llm.usage.completion_tokensCanonical token attribute written by the SDK processors.
llm.usage.total_tokensCanonical total token count.
llm.usage.sourceWhere 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:

bash
# Pull the latest from the Traccia platform (or upstream if platform unreachable)
traccia pricing refresh
# Check the current snapshot age and source
traccia pricing status
# Force upstream (no account needed)
traccia pricing refresh --source upstream

Snapshot > 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

Run 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.

python
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.

bash
export TRACCIA_PRICING_OVERRIDE_JSON='{"gpt-4o": {"prompt": 0.005, "completion": 0.015}}'

Deprecation: AGENT_DASHBOARD_PRICING_JSON

The legacy 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

json
{
"<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.

python
# Tool span — no llm.cost.usd added
with span("search_web", {"span.type": "tool"}) as s:
results = search(query)
# LLM span — cost calculated normally
with 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):

python
# Programmatic
traccia.init(enable_costs=False)
# Environment variable
# TRACCIA_ENABLE_COSTS=false
# traccia.toml
# [instrumentation]
# enable_costs = false

Platform costs still work

Disabling SDK-side cost estimation does not affect platform recomputation. As long as the span carries 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.

AspectSDK (llm.cost.usd)Platform (platform_cost_usd)
When computedAt span end, in your processAsynchronously after ingestion (~15s)
Pricing sourceLocal snapshot (bundled / cache / override)Platform snapshot + org overrides
Org overrides appliedNoYes
MutableNever changed after emitUpdated on recomputation
Visible in UISecondary — shown in span detail panelPrimary — shown everywhere

See Platform Costs for a detailed explanation of divergence scenarios and how to resolve them.

See Also

© 2026 Traccia.