> ## Documentation Index
> Fetch the complete documentation index at: https://docs.honeycomb.io/llms.txt
> Use this file to discover all available pages before exploring further.

# How Honeycomb Calculates LLM Costs

> Learn about LLM cost tracking in Honeycomb and how you can compare relative spend across models, services, and features.

Honeycomb enriches spans describing calls to large language models (LLM) with an estimated US dollar cost.
LLM costs are calculated at ingest, based on the token counts your instrumentation reports and [Pydantic's pricing catalog](https://github.com/pydantic/genai-prices).
These LLM costs are added to your spans as fields you can query, group, and visualize.

<Warning>
  LLM cost is a catalog estimate, not a billed amount.
  It does not reflect negotiated rates, committed-use discounts, free tiers, or credits.
  Do not use it to reconcile a provider invoice.
</Warning>

## Attributes used to calculate cost

The estimated total cost (`io.honeycomb.gen_ai.cost.estimated_total_cost`) is calculated from:

* Input (prompt) and output (completion) tokens
* Cached token reads and writes (when applicable)
* AI model and provider

Honeycomb reads standard [OpenTelemetry GenAI semantic convention attributes (v1.41.1)](https://github.com/open-telemetry/semantic-conventions-genai).
If your application uses an OpenTelemetry-based GenAI instrumentation library, these attributes are likely already on your spans.

| Purpose            | Attribute                                  | Fallback                                   |
| ------------------ | ------------------------------------------ | ------------------------------------------ |
| Model              | `gen_ai.response.model`                    | `gen_ai.request.model`                     |
| Provider           | `gen_ai.provider.name`                     | `gen_ai.system`                            |
| Operation          | `gen_ai.operation.name`                    | none                                       |
| Input tokens       | `gen_ai.usage.input_tokens`                | `gen_ai.usage.prompt_tokens`               |
| Output tokens      | `gen_ai.usage.output_tokens`               | `gen_ai.usage.completion_tokens`           |
| Cache write tokens | `gen_ai.usage.cache_creation.input_tokens` | `gen_ai.usage.cache_creation_input_tokens` |
| Cache read tokens  | `gen_ai.usage.cache_read.input_tokens`     | `gen_ai.usage.cache_read_input_tokens`     |

Honeycomb reads a fallback name only when the preferred name is absent or empty.

The two cache counts are subsets of `gen_ai.usage.input_tokens`, not additions to it.
Honeycomb prices them out of that same input total at their own rates, so a cache read is never double-counted.

## How LLM span cost is calculated

A span's cost is calculated only when all of the following are true.
The following checks run in order, and the first failure stops the calculation.

<Steps>
  <Step title="The span names a model.">
    `gen_ai.response.model`, or else `gen_ai.request.model`.
  </Step>

  <Step title="The span does not already carry a cost.">
    See [when you report your own cost](#reporting-your-own-genai-cost-estimates).
  </Step>

  <Step title="The operation accounts for tokens.">
    One of `chat`, `text_completion`, `generate_content`, `embeddings`, or `retrieval`. Aliases resolve first, so `chat_completion` counts as `chat`.

    Operations such `invoke_agent`, `create_agent`, `execute_tool`, or `invoke_workflow` are not priced, because their cost is already captured by the inference spans beneath them.
  </Step>

  <Step title="The provider is supported.">
    `openai`, `anthropic`, or `aws.bedrock`. The comparison is case-insensitive and ignores surrounding whitespace. More providers are planned.
  </Step>

  <Step title="The span reports token counts.">
    At least one of `gen_ai.usage.input_tokens` or `gen_ai.usage.output_tokens`.
  </Step>

  <Step title="The model appears in the pricing catalog.">
    New model releases can take a short time to appear.
  </Step>
</Steps>

A missing operation name or a missing provider fails its check.
When a span fails any check, Honeycomb adds no cost fields to the span and changes nothing your instrumentation sent.

<Note>
  Honeycomb searches the catalog for your reported provider first, then the whole catalog.
  That second pass prices a Bedrock-hosted Anthropic model, whose rates are published by Anthropic rather than AWS.
  On those spans, `gen_ai.provider.name` is `aws.bedrock` while `io.honeycomb.gen_ai.cost.pricing_provider` is `anthropic`.
  The two fields are expected to be different. This is not a bug.
</Note>

## LLM cost fields Honeycomb adds

Honeycomb writes seven fields in the [`io.honeycomb.gen_ai.cost` namespace](#about-the-io-honeycomb-namespace).

<ResponseField name="io.honeycomb.gen_ai.cost.estimated_input_cost" type="double">
  Estimated cost of the input tokens in US dollars.
</ResponseField>

<ResponseField name="io.honeycomb.gen_ai.cost.estimated_output_cost" type="double">
  Estimated cost of the output tokens in US dollars.
</ResponseField>

<ResponseField name="io.honeycomb.gen_ai.cost.estimated_total_cost" type="double">
  Estimated cost of the whole LLM call in US dollars.
</ResponseField>

<ResponseField name="io.honeycomb.gen_ai.cost.pricing_provider" type="string">
  The provider whose rates were applied.
</ResponseField>

<ResponseField name="io.honeycomb.gen_ai.cost.pricing_library" type="string">
  The pricing library that performed the calculation.
</ResponseField>

<ResponseField name="io.honeycomb.gen_ai.cost.pricing_data_source" type="string">
  The source of the rate data.
</ResponseField>

<ResponseField name="io.honeycomb.gen_ai.cost.pricing_version" type="string">
  The version of the price table applied.
</ResponseField>

The four `pricing_*` fields record what produced the estimate, so you can trace any cost estimate back to the price table used to calculate it.
The `pricing_*` fields are written as a set of four, or not at all.

Honeycomb reports three cost figures only.
There is no separate cost field for cache reads, cache writes, or reasoning tokens, even though those counts feed the calculation.
To see where a rate difference shows up, group by model and provider.

### About the `io.honeycomb.*` namespace

The `io.honeycomb.*` namespace is an incubating space for attributes Honeycomb is also pursuing upstream in the OpenTelemetry semantic conventions.

Honeycomb defines an allowlist of `io.honeycomb.*` keys and what each key means. Undeclared `io.honeycomb.*` keys are dropped at ingest. If you provide your own values, they are never overwritten.

## Reporting your own LLM costs

Honeycomb never overwrites a cost your instrumentation reported.
If **any one** of the three cost fields is present on the span, Honeycomb writes none of the seven.

This matters when your provider reports an authoritative per-call cost a catalog cannot reproduce.
For example, an OpenRouter call may route to a different upstream provider on every request, so only the response knows what it cost.
Send that figure and Honeycomb leaves it alone.

| What your instrumentation sends      | What Honeycomb writes                                                                   |
| ------------------------------------ | --------------------------------------------------------------------------------------- |
| Nothing in the namespace             | All seven fields, if the span can be priced.                                            |
| One cost field                       | Nothing. Your value stands alone, with no total and no provenance.                      |
| Input and output cost, no total      | Nothing. The span has no total cost.                                                    |
| All three cost fields                | Nothing. No provenance is added.                                                        |
| A `pricing_*` field only             | All seven fields, overwriting yours — if the span can be priced. If it cannot, nothing. |
| A cost field and a `pricing_*` field | Nothing. Both of your values remain.                                                    |
| A cost field, but no model           | Nothing. Your values remain.                                                            |

Honeycomb never deletes a key you sent. To summarize the table above:

* **Honeycomb does not complete a partial set.** A total assembled from your two figures and Honeycomb's arithmetic would be neither yours nor ours, and no consumer of the field could tell which. Send all three, or send none.
* **A cost of `0` counts as a reported cost.** The check tests whether the field is present, not its value. To have Honeycomb price a call, omit the field rather than sending zero.
* **`pricing_*` fields are the overwrite exception.** They name what computed the estimate, so leaving yours in place would credit Honeycomb's number to a source that did not produce it. One edge case: if you send a `pricing_*` field and the span cannot be priced, it stays with no cost field to explain it.

## Where cost appears in Honeycomb

The seven fields are ordinary public fields on your dataset, and are available regardless of whether any LLM cost-specific UI is enabled for your team.
They appear in the field picker, are queryable by name, and work with `SUM`, `AVG`, `HEATMAP`, `P95`, and any other numeric operator.
The cost fields also work in Triggers, SLOs, Boards, and Calculated Fields.

## Example cost estimation queries

### Cost by model or service

Find the estimated total cost of each LLM model or service.

| SELECT                                                | WHERE                                                   | GROUP BY                              |
| ----------------------------------------------------- | ------------------------------------------------------- | ------------------------------------- |
| SUM(io.honeycomb.gen\_ai.cost.estimated\_total\_cost) | io.honeycomb.gen\_ai.cost.estimated\_total\_cost exists | gen\_ai.request.model or service.name |

### Cost per user

See the average cost per user or tenant.

| SELECT                                                | WHERE                                                   | GROUP BY             |
| ----------------------------------------------------- | ------------------------------------------------------- | -------------------- |
| AVG(io.honeycomb.gen\_ai.cost.estimated\_total\_cost) | io.honeycomb.gen\_ai.cost.estimated\_total\_cost exists | user or tenant field |

Here are some useful queries you can run with the cost estimation fields:

### Identify GenAI call cost outliers

Find cost outlier GenAI calls, then use BubbleUp to investigate further.

| SELECT                                                    | WHERE                                                   |
| --------------------------------------------------------- | ------------------------------------------------------- |
| HEATMAP(io.honeycomb.gen\_ai.cost.estimated\_total\_cost) | io.honeycomb.gen\_ai.cost.estimated\_total\_cost exists |

## Limitations

* The cost estimate is a catalog price, not your invoice.
* A span with no token counts cannot be priced, so a streaming call that never reports usage produces no cost.
* Agent, tool, and workflow spans are not priced. Cost accrues on the inference spans they contain.
* If a model is missing from the catalog, no cost estimate is calculated.
* Cost is estimated per call. You can use queries to aggregate to the trace or session.
