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

> Find which GenAI attributes Honeycomb uses to estimate LLM cost at ingest, the cost fields it adds to your spans, and how to query or override them

<Badge className="hny-badge-early-access" stroke>Early Access (EA)</Badge>

<Info>
  LLM cost estimation is available in Early Access (EA).
  Contact your Honeycomb account team for more information.
</Info>

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.">
    Honeycomb skips spans that already carry a cost, as described in [Reporting your own LLM costs](#reporting-your-own-llm-costs).
  </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 as `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.
  </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

If you'd like to report your own LLM cost estimates, your telemetry should provide values for the estimated cost fields in the `io.honeycomb.gen_ai.cost` namespace.
Honeycomb does not write anything to the `io.honeycomb.gen_ai.cost` namespace if any one of these cost fields is present on the span with a value:

* `io.honeycomb.gen_ai.cost.estimated_input_cost`
* `io.honeycomb.gen_ai.cost.estimated_output_cost`
* `io.honeycomb.gen_ai.cost.estimated_total_cost`

A cost of `0` counts as a reported cost.

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

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