# No cost displayed in LangSmith when using LiteLLM + LangGraph

**URL:** <https://forum.langchain.com/t/no-cost-displayed-in-langsmith-when-using-litellm-langgraph/3426>\
**Category:** LangGraph\
**Tags:** intro-to-langgraph, intro-to-langsmith, python-help\
**Created:** [April 16, 2026, 6:39pm UTC](https://forum.langchain.com/t/no-cost-displayed-in-langsmith-when-using-litellm-langgraph/3426 "2026-04-16T18:39:38Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![VettHor](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/vetthor/32/765_2.png) [@VettHor](https://forum.langchain.com/u/VettHor)\
**Post date:** [April 16, 2026, 6:39pm UTC](https://forum.langchain.com/t/no-cost-displayed-in-langsmith-when-using-litellm-langgraph/3426/1 "2026-04-16T18:39:38Z")

</div>

Hey, I’m using `ChatLiteLLMRouter` with LangGraph. Token count is tracked correctly in LangSmith, but cost is never shown - for any model (OpenAI, Anthropic, Gemini).

I tried adding `langsmith` callback as described [here](https://docs.litellm.ai/docs/observability/langsmith_integration):

```auto
import litellm
from langchain_litellm import ChatLiteLLMRouter

litellm.success_callback = ["langsmith"]

llm = ChatLiteLLMRouter( # then use `llm` in my graph
   router=litellm_router,
   model="heavy",
   temperature=0,
   streaming=True,
)

```

This does show tokens + cost, but creates separate traces for each LLM call - outside my graph trace. And it’s not even consistent - as you can see in the screenshot, the first separate trace (Gemini) shows no cost at all, while the rest (Anthropic) do:

 ![image](https://canada1.discourse-cdn.com/flex007/uploads/langchain/original/2X/4/4b433b0d1894091cc8fb2483b85c01d794c87690.png)

I don’t want that. What I want is the standard LangSmith behaviour:

- Root graph run shows total tokens + total cost
- Drilling into the run shows per-step token/cost breakdown

Do I need to write custom callbacks to achieve this? Any tips how to do it? Is there a built-in way? Should I do smth like described [here](https://docs.langchain.com/langsmith/cost-tracking#a-set-a-usage-metadata-field-on-the-runs-metadata)?

Thanks in advance!

---

<div class="post-metadata">

**Author:** ![pawel-twardziak](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/pawel-twardziak/32/960_2.png) [@pawel-twardziak](https://forum.langchain.com/u/pawel-twardziak)\
**Post date:** [April 16, 2026, 7:46pm UTC](https://forum.langchain.com/t/no-cost-displayed-in-langsmith-when-using-litellm-langgraph/3426/2 "2026-04-16T19:46:29Z")

</div>

hi @VettHor

the docs page you linked - [“a. Set a `usage_metadata` field on the run’s metadata”](https://docs.langchain.com/langsmith/cost-tracking#a-set-a-usage-metadata-field-on-the-runs-metadata) - is the right mental model, but it’s only step 1 of the cost pipeline: `run.set(usage_metadata=...)` only delivers tokens (or, optionally, raw `input_cost`/`output_cost`), it doesn’t _price_ anything by itself. LangSmith prices a run only when three things are present together - a `usage_metadata` block, the pair `ls_provider` + `ls_model_name` on the run, and a matching regex row in _Settings → Workspace → Models_ ([Cost tracking](https://docs.langchain.com/langsmith/cost-tracking), [Metadata reference](https://docs.langchain.com/langsmith/ls-metadata-parameters)). `ChatLiteLLMRouter` never emits the `ls_*` pair (no `_get_ls_params()` override) and its `response_metadata.model_name` is the router _group_ (e.g. `"heavy"`), not the model LiteLLM actually dispatched to - so LangSmith sees tokens with nothing to price them against, which is why cost is blank and why any occasional Anthropic figure is a misleading partial-match, not real tracking. The fix is to stop using `litellm.success_callback = ["langsmith"]` (it posts sibling traces outside your LangGraph tree) and instead apply that docs pattern from inside LangChain’s callback lifecycle: either (a) subclass the router and implement `_get_ls_params()` that reads the real model from LiteLLM’s `response["model"]` in `_create_chat_result`, then add matching pricing rows in the workspace; (a′) attach a `BaseCallbackHandler` whose `on_llm_end` patches the run’s metadata with `ls_provider`/`ls_model_name` - this is the direct LangGraph equivalent of the snippet on the page you linked; or (b) for non-linear pricing, compute the dollar amount with `litellm.completion_cost()` and write it onto the current run via `get_current_run_tree().set(usage_metadata={"input_cost": ..., "output_cost": ...})` - all three keep everything inside one nested LangGraph trace with correct per-node cost aggregation.

---

<div class="post-metadata">

**Author:** ![dualdust](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/dualdust/32/3250_2.png) [@dualdust](https://forum.langchain.com/u/dualdust)\
**Post date:** [July 7, 2026, 3:10pm UTC](https://forum.langchain.com/t/no-cost-displayed-in-langsmith-when-using-litellm-langgraph/3426/3 "2026-07-07T15:10:34Z")

</div>

I would separate this into two layers:

1. provider-level accounting: what the LiteLLM router knows about the concrete model, input tokens, output tokens, and cost
2. graph-level accounting: how those numbers are attached back to the LangGraph run/span you actually care about

If tokens are appearing but cost is missing, I would first check whether the model alias resolves to a pricing-aware model name before it reaches LangSmith. A lot of cost dashboards break at the alias layer: “heavy” is meaningful to the router, but not necessarily meaningful to the tracing layer.

The pattern I would try is to attach normalized usage metadata at the node boundary, not only through the global LiteLLM callback. That keeps the cost attribution inside the graph trace and avoids having separate LLM traces floating outside the run.

For production, I would also log cost by workflow/user/customer at the same time as the LangSmith trace id. The trace answers “where did tokens go?” but the product question is usually “which workflow or tenant made this expensive?”
