> This page is for Gateway.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.merge.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.merge.dev/_mcp/server.

# Telemetry export

> Export Gateway traces and metrics as OTLP to Datadog, Grafana Cloud, or any OTLP endpoint, with prompt content excluded unless you turn it on.

Telemetry export sends one span per Gateway request to your own observability backend, so LLM traffic sits beside the rest of your system with no code changes. Spans go out as [OTLP](https://opentelemetry.io/docs/specs/otlp/) over HTTP/protobuf, following the OpenTelemetry GenAI semantic conventions.

## Set up a destination

Open **Settings → Telemetry export** and click **Add destination**, or call [`POST /v1/export-destinations`](/merge-gateway/management-api/export-destinations/create-export-destination). This needs **Manage telemetry export** (Admin and Developer roles).

| Destination       | Target field                                                                                                                             | Credential                                        | Traces land in    |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ----------------- |
| **Datadog**       | **Datadog site**: `datadoghq.com`, `us3.datadoghq.com`, `us5.datadoghq.com`, `datadoghq.eu`, `ap1.datadoghq.com`, or `ap2.datadoghq.com` | **API key**                                       | LLM Observability |
| **Grafana Cloud** | **Zone**, such as `prod-us-east-0` from `otlp-gateway-prod-us-east-0.grafana.net`                                                        | **Instance ID** and **Access policy token**       | Tempo             |
| **Custom (OTLP)** | **Endpoint URL**, the base URL only. Gateway appends `/v1/traces` and `/v1/metrics`.                                                     | **Bearer token**, sent as `Authorization: Bearer` | Your endpoint     |

**Custom (OTLP)** needs Enterprise and accepts any OTLP/HTTP receiver: an OpenTelemetry Collector, Honeycomb, New Relic, SigNoz, Langfuse, or self-hosted Tempo or Jaeger. It must use `https` and can't redirect or resolve to a private, loopback, link-local, reserved, or cloud metadata address.

**ML app** (**Service name** for Grafana and custom) sets `service.name`, defaulting to the destination name. Each enabled destination gets all your organization's traffic, so a second one copies rather than splits it.

## Prompts and completions

**Exclude prompts and completions** is on by default. It strips `gen_ai.input.messages`, `gen_ai.output.messages`, `gen_ai.tool.definitions`, and error messages (which can quote the prompt); models, tokens, latency, and cost still arrive. Turning it off sends content to that destination, independent of Gateway's own payload logging. It's re-read before each batch, so re-enabling it stops content immediately, even for queued requests.

## Metrics

**Send metrics** (off by default) adds:

| Metric                              | Type                              |
| ----------------------------------- | --------------------------------- |
| `gen_ai.client.operation.duration`  | Histogram, seconds                |
| `gen_ai.client.token.usage`         | Histogram, by `gen_ai.token.type` |
| `gen_ai.client.time_to_first_token` | Histogram, seconds                |
| `merge.cost.usd`                    | Sum                               |

> **Leave metrics off for Grafana Cloud**
>
> Metrics use delta temporality, which Datadog requires and Grafana Cloud's OTLP gateway rejects with `invalid temporality and type combination`. The dashboard still allows the toggle, but points are rejected (traces still reach Tempo). Derive span metrics with Tempo's metrics generator instead.

Spans carry the same numbers and Datadog bills custom metrics separately, so enable metrics for long retention, cheap wide-range queries, or alerts. In Datadog, attribute keys keep their dots (group by `{merge.cost.basis}`), and histogram percentile queries need percentiles enabled on the metric first.

## Delivery

Gateway batches spans per destination and retries transient failures with backoff; a rejected credential or malformed endpoint isn't retried. Repeated failures pause that destination for a while before Gateway retries. Export runs outside the request path, so a failing destination never affects your LLM calls. Spans usually arrive within a few minutes, plus a few more in Datadog LLM Observability.

## Reference

| Attribute                                                                          | Meaning                                                                                |
| ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `gen_ai.operation.name`                                                            | `chat`, `embeddings`, `image_generation`, `speech_synthesis`, or `audio_transcription` |
| `gen_ai.request.model`, `gen_ai.response.model`                                    | Requested and served model                                                             |
| `gen_ai.provider.name`                                                             | Semconv provider name, such as `aws.bedrock`                                           |
| `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`                          | Token counts                                                                           |
| `gen_ai.usage.cache_read.input_tokens`, `gen_ai.usage.cache_creation.input_tokens` | Prompt cache activity                                                                  |
| `gen_ai.conversation.id`                                                           | Session ID, when the request carried one                                               |
| `gen_ai.input.messages`, `gen_ai.output.messages`, `gen_ai.tool.definitions`       | Content, only when prompts and completions aren't excluded                             |
| `merge.request_id`, `merge.project_id`, `merge.customer_id`                        | Gateway request, project, and customer IDs                                             |
| `merge.vendor`, `merge.was_fallback`, `merge.fallback_reason`                      | Serving vendor and whether a fallback served the request                               |
| `merge.cost.usd`, `merge.cost.basis`                                               | Cost and what it measures                                                              |
| `error.type`                                                                       | Error code, on failed requests                                                         |

`merge.cost.basis` says whose charge `merge.cost.usd` is:

| Basis                 | `merge.cost.usd` is                                                 |
| --------------------- | ------------------------------------------------------------------- |
| `merge_billed`        | What you pay Merge for the request                                  |
| `provider_list_price` | The vendor's list price for BYOK traffic, which you pay your vendor |
| `unavailable`         | Omitted, because Gateway couldn't price the request                 |

Sum both priced bases for total LLM spend. A `merge_billed` `0` means the request used no tokens.

## Next steps

#### [Tracing](/merge-gateway/observability/tracing)

Group requests into traces and threads in Logs

#### [Audit trail](/merge-gateway/security/audit-trail)

Review security and configuration events