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

# Traces

> Store and explore OpenTelemetry traces and logs from your voice agents — one trace per call, a tree of spans.

Traces are the OpenTelemetry view of what happened inside a call. One call or
session is one **trace**: a tree of **spans** (an LLM generation, a
text-to-speech step, a speech-to-text step, a tool call, your own code) plus the
**logs** those steps emit. Zelto stores this telemetry so you can see, per call,
where the time and tokens went and what failed — replacing a separate
Langfuse-plus-logging stack.

Open **Traces** in the sidebar to see the list: one row per trace, with the root
span, the kinds of spans present, span count, latency, tokens, cost, and status.
Click a row for a quick summary, then open the full **waterfall** to walk the
span tree, read each span's input/output and attributes, and see its logs.

## What a trace holds

* **Spans**, each tagged with a normalized kind: `llm`, `tts`, `stt`, `vad`,
  `tool`, `code`, `telephony`, `livekit`, `session`, or `other`. GenAI spans
  carry model, token, and cost fields promoted for fast filtering.
* **Logs**, attached to a span or to the trace as a whole, with a severity and
  body.
* A **session reference** (room / call / session id) that links a trace back to
  its [conversation](/docs/conversations) when the two can be matched.

Traces are retained for 90 days.

## Send telemetry

<Note>
  If your calls come from [Vapi](/docs/integrations/vapi), you get traces for
  free — Zelto turns each pulled call's Vapi platform logs into a trace, with no
  exporter to install. See
  [Vapi → Traces](/docs/integrations/vapi#traces-without-instrumenting-anything).
</Note>

Traces is fed by standard **OTLP/HTTP**, so any agent with an OpenTelemetry
exporter works — including a [LiveKit](/docs/integrations/livekit) agent, whose
sessions LiveKit auto-instruments. There's no Zelto-specific client code to
write, but you do register an OTLP exporter pointed at Zelto — a few lines in
your agent (see [LiveKit](/docs/integrations/livekit#stream-traces-opentelemetry)
for the exact snippet). Open **Traces** and use **Connect agent** to create a
per-organization, write-only **observability ingest key** (shown once) and copy
the exporter config. Creating and revoking ingest keys needs the `owner` or
`admin` [role](/docs/settings#members--invites). Point your exporter at Zelto's
ingest host and authenticate with that key (a bearer token):

```bash theme={null}
OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.zelto.ai"
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <your-ingest-key>"
OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
```

The exporter posts spans to `/v1/traces` and logs to `/v1/logs` — the
OpenTelemetry SDK appends those paths to the endpoint above for you. Both
OTLP/HTTP encodings are accepted — **protobuf** (what most exporters send by
default, including the OpenTelemetry Python SDK a LiveKit agent uses) and
**JSON** — so you don't have to match a specific one. gRPC (`:4317`) is not
accepted; use the HTTP endpoint above.

<Note>
  The OpenTelemetry **Python** SDK (which LiveKit's agents run on) sends
  `http/protobuf` and does not implement `http/json`, so leave
  `OTEL_EXPORTER_OTLP_PROTOCOL` at `http/protobuf` (its default). Zelto accepts
  both encodings regardless.
</Note>

Ingestion is rate-limited per organization. If you export at a very high rate,
some requests get a `429` with a `Retry-After` header — standard OpenTelemetry
exporters honor it and back off automatically, so no batches are lost. If your
agent legitimately exports at a high volume, ask your Zelto contact to raise the
per-organization ingest rate.

<Note>
  If traces aren't appearing, confirm the exporter is pointed at the ingest host
  above and is sending a valid `Authorization: Bearer` ingest key.
</Note>

### Native JSON

If your agent doesn't speak OTLP, post a simpler Zelto-native JSON body of spans
and logs to `/webhooks/otel` with the same bearer key. Use OTLP where you can —
it's the zero-code path.

## Backfill from tool calls

Already recording tool calls but not yet exporting OpenTelemetry? Zelto can
project your existing tool-call history into traces so the view isn't empty
while you wire up an exporter — each tool call becomes a `tool` span, and a
call's tool calls share one trace. Only calls from the last 90 days are kept (the
trace retention window). Ask your Zelto contact to run the tool-call backfill for
your organization.

## Related

* [Conversations](/docs/conversations) — the transcript-and-analysis view of a
  call; a trace links to its conversation when the session id matches.
* [LiveKit](/docs/integrations/livekit) — point a LiveKit agent's OpenTelemetry
  exporter at Zelto to stream traces.
