How do I track LLM cost per request?
Rius gives you the cost of each request as the cost of its trace, computed from the model name and token counts on the spans, so you never send a cost value. Each model call is priced when it arrives, and you read the cost per trace in the console or over MCP. Put session.id and user.id on the spans to split the same cost by session and by end user.
How it works
A request is one trace, and its cost is the sum of the priced model calls inside it. For each model call, Rius looks up the requested model in LiteLLM’s public model-price catalog and multiplies every token count by its own rate. Prices are in US dollars, and the result is a list-price estimate, not a billed amount.
These attributes on a span make that work:
gen_ai.request.model: the model name. A span that carries onlygen_ai.response.modelis not priced.gen_ai.usage.input_tokens: the total prompt, including cached tokens.gen_ai.usage.output_tokens: the completion tokens.gen_ai.usage.cache_read.input_tokensandgen_ai.usage.cache_write.input_tokens: priced at the provider’s cache rates.
OpenInference and OpenLLMetry equivalents of the token keys are normalized at ingest. Do not send a cost attribute, because Rius ignores it.
To split by who or what caused the request, set session.id and user.id on every span, root span included. Without a session.id, each trace is its own session. Without a user.id, the trace counts as anonymous. Prefer an opaque user id to an email.
If the model is not in the catalog, or the span reports no token usage, the cost stays empty, not zero, so an unpriced call never looks free. Totals add up only the priced calls.
Set it up
- Send traces with the SDK, and wrap the function that handles one request so each request becomes one trace. The quickstart does this with
rius.observe. The full install is in the SDK installation guide.
import anthropic
import rius
rius.init(api_key="ri_...", service_name="my-agent")
claude = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
@rius.observe
def handle(query: str) -> str:
response = claude.messages.create(
model="claude-haiku-4-5-20251001",
max_tokens=200,
messages=[{"role": "user", "content": query}],
)
return response.content[0].text
handle("What should I check when a collector drops spans?")- Open Traces, pick a trace, and select one model call. The span detail shows the provider, the requested and response model, the input and output tokens, and the cost. If the model or the tokens are missing there, the span cannot be priced, and the cost is blank.
- Tag requests with
session.idanduser.idon every span. In Python you set them withrius.sessionandrius.user. In TypeScript you usewithSessionandwithUser.RIUS_SESSION_IDsets a session for a whole process, and there is no environment variable for the user. - Check that cost resolves for your models in the cost by model chart on Usage and cost. It notes the share of LLM calls that were priced. The pricing rules are covered in Track LLM and agent cost.
What you get
In the console
- On Traces, each row shows the computed cost of that request. The strip above the list sums cost for the traces that match your filters, and the trace header shows the total for one run. See Exploring traces.
- The Map tab has a cost lens, so you can see which step in one request spent the money.
- The Spans tab lists individual calls. Click the Cost header to sort the most expensive ones to the top, or filter to one kind of step, such as LLM calls.
- You can filter the trace list by any attribute your spans carry, such as
user.id. Filters live in the URL, so a copied link opens the same list. - On Users, each end user shows total cost and average cost per trace. Sort by Cost to find the most expensive ones.
- Agents shows cost per trace for each agent, and Compare puts two agent versions side by side.
- On Home, the workspace total, per-trace and per-1k-token averages, and cost by model are in Usage and cost.
Over MCP
Connect an MCP client and ask in plain language, for example who your ten most expensive end users were this week. The client calls list_agent_traces and list_spans for individual requests and calls. It uses agent_traces_summary for one agent or service, list_users for users sorted by cost, and workspace_metrics_overview for the workspace total and cost by model.
A total with nothing priced in it shows a dash in the console. agent_traces_summary reports the same case as $0.00.
When something else fits
- Costs are list-price estimates at standard rates. They leave out long-context tiers, batch, flex or priority pricing and negotiated discounts, so your provider invoice is the source for exact billing.
- If you run one workspace per customer, the workspace total is that customer’s cost, and you do not need
user.idfor that split. - Cost alerts work per trace, for example p95 cost over a threshold. A total-spend threshold for the whole workspace is not an alert metric, so watch that total on Home.