What Is OTLP?

OTLP

OTLP (OpenTelemetry Protocol) is the standard protocol for sending traces, metrics, and logs from an application to a collector or backend. For AI agents, OTLP is how spans describing each model call and tool call travel from your code to the system where you inspect them.

For example, suppose a Python agent records a trace for each run, with one span for the agent, one for each LLM call, and one for each tool call. An OTLP exporter sends those spans over gRPC to port 4317 on your backend. If the backend only accepts HTTP on port 4318, the spans never arrive, even though the agent itself runs fine.

OTLP defines the data format and how it is transported. It does not define how you instrument your code or how the backend stores the data.

Try Arize AX

Build better agents with Arize

Trace, evaluate, and learn. Build agents that work with Arize AX and start tracing your runs today.

Prefer open source? Try Arize Phoenix for self-hosted, open source agent observability.

Why OTLP matters

Telemetry is only useful if it reaches a system where you can query it. OTLP gives every compliant application and backend a shared format, so you can change backends without re-instrumenting your code.

OTLP is useful for:

  • Exporting agent traces: Send spans for model calls, tool calls, and retrieval steps to an observability backend.
  • Avoiding vendor lock-in: Point the same exporter at any backend that accepts OTLP.
  • Routing telemetry: Send data through an OpenTelemetry Collector that batches, filters, or fans it out to several backends.
  • Debugging missing data: Separate transport problems from instrumentation problems when traces do not appear.

For background on what a trace contains, see trace.

How OTLP works

OTLP sits between your instrumented application and the backend. The path has three steps.

  1. Your application records telemetry with an OpenTelemetry SDK (software development kit) or an instrumentation library.
  2. An exporter encodes that telemetry according to the OTLP specification.
  3. The exporter sends it to an endpoint. That endpoint is either a backend that accepts OTLP or an OpenTelemetry Collector that can receive, process, batch, and forward it.

The model of traces and spans that OTLP carries is described in the OpenTelemetry traces overview.

One endpoint per signal

OpenTelemetry calls each kind of telemetry a signal. OTLP defines one request shape for each of the three signals.

POST /v1/traces    (traces)      gRPC service: opentelemetry.proto.collector.trace.v1.TraceService
POST /v1/metrics   (metrics)     gRPC service: opentelemetry.proto.collector.metrics.v1.MetricsService
POST /v1/logs      (logs)        gRPC service: opentelemetry.proto.collector.logs.v1.LogsService

The paths on the left are the OTLP/HTTP endpoints. The gRPC transport uses the matching collector services on its own port.

Two transports and two encodings

OTLP runs over two transports:

  • gRPC: Conventionally on port 4317.
  • HTTP: Conventionally on port 4318.

Payloads use Protocol Buffers (protobuf) by default, sent with Content-Type: application/x-protobuf. Over HTTP, JSON (application/json) is also permitted.

Because OTLP is a published specification rather than a vendor format, any compliant backend can receive the same export. That is the practical point of the protocol.

How to configure an OTLP exporter

Most OpenTelemetry SDKs read their exporter settings from the same environment variables, whatever the language. The example below sets the endpoint, the protocol, and the headers the backend requires.

export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel.example.com:4317"
export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"        # or http/protobuf, http/json
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer%20<token>,x-project=<project>"  # values are URL-encoded: %20 is the space

Here is what each variable controls:

  • OTEL_EXPORTER_OTLP_ENDPOINT: The host and port the exporter sends to.
  • OTEL_EXPORTER_OTLP_PROTOCOL: The transport and encoding. It must match what the receiver listens for on that port.
  • OTEL_EXPORTER_OTLP_HEADERS: Key-value pairs sent with each request, usually credentials and project identifiers.

Signal-specific variables override the generic endpoint. For example, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT lets traces go somewhere different from metrics.

The receiving backend sets the header names and required values. Treat the values above as placeholders, and take the real ones from your backend’s setup guide. For Arize, see the Phoenix documentation and the AX documentation.

Worked example: exporting an agent trace

Consider a Python agent instrumented with OpenInference. Each run produces a trace with three kinds of spans:

  • A root agent span for the whole run.
  • Child LLM spans that include token counts.
  • Tool spans that include arguments and results.

OpenInference defines what those spans contain. OTLP’s job starts after the spans exist.

agent process
  └─ OpenInference instrumentation creates spans
  └─ OpenTelemetry SDK batches finished spans
  └─ OTLP exporter (gRPC, port 4317) sends ExportTraceServiceRequest
       └─ Collector or backend receives, stores, indexes
            └─ trace appears for inspection in the backend UI

Debugging a trace that never appears

If the trace never shows up, check each layer in order:

  1. Span creation: Are spans being created at all? Enable SDK console output or a local file exporter to find out.
  2. Endpoint and protocol: Is the exporter pointed at the host, port, and protocol the receiver listens on? Sending HTTP to a gRPC port, or the reverse, is the single most common failure.
  3. Headers: Do the headers carry the credentials and project identifiers the backend requires?
  4. Rejection vs. network loss: Did the receiver reject the payload, or did the network drop it? Check the exporter’s error logs and the receiver’s response codes.

This order proves local span creation first, then transport, then ingestion. It mirrors how distributed tracing systems are usually brought up.

OTLP vs. OpenTelemetry and other common confusions

OTLP vs. OpenTelemetry: OpenTelemetry is the umbrella project. It includes APIs (application programming interfaces), SDKs, instrumentation libraries, semantic conventions, the Collector, and the protocol. OTLP is only the protocol specification.

Saying “we send OpenTelemetry” is shorthand. Saying “we export OTLP/gRPC to the Collector” is precise.

OTLP vs. OpenInference: OTLP defines how telemetry travels. OpenInference defines what large language model (LLM) telemetry means, including span kinds and attributes for prompts, completions, embeddings, and tools. An export can be valid OTLP and still be hard to use if its spans carry no LLM attributes.

OTLP vs. a vendor agent or file format: OTLP is not an agent you install, a log file format, or a query language. Storage, indexing, and querying belong to the backend. For more on that layer, see AI observability.

OTLP/HTTP vs. OTLP/gRPC: Both carry the same data model over different transports. gRPC is the conventional choice for high-throughput collector pipelines. HTTP with JSON is easier to debug with ordinary HTTP tools and passes through more proxies. Both are standards-compliant, and the receiver’s supported transports decide which you use.

Limitations of OTLP

  • Transport, not meaning: Two systems can exchange valid OTLP while disagreeing about attribute names, span semantics, or how a session is represented. Semantic conventions still matter after the protocol works.
  • No sampling for you: Exporting everything can swamp networks and backends on high-volume agents. Sampling decisions made in the SDK are invisible in the data that arrives.
  • Silent failures: The application keeps running while telemetry is dropped. Exporter errors need their own logging and alerting.
  • Batching delay: The SDK’s batch span processor holds spans briefly before handing them to the exporter. Spans still in memory are lost if the process crashes before export.
  • Credential exposure: Headers carry credentials. An endpoint and header pasted into a public repository, or a header logged at debug level, is a credential leak.

OTLP’s convenience makes that last mistake easy, because a single environment variable can hold the credentials.

Frequently asked questions

Which OTLP port and protocol should I use?

Use whatever your receiver documents. The conventions are port 4317 for OTLP/gRPC and port 4318 for OTLP/HTTP. A mismatch between the protocol you send and the port you send it to is the most common reason a correctly instrumented application exports nothing.

Do I need an OpenTelemetry Collector to use OTLP?

No. Many backends accept OTLP directly from the application’s exporter. A Collector becomes useful when you need fan-out to several backends, central batching or sampling, attribute processing, or a network boundary between applications and backends.

Can OTLP carry logs and metrics as well as traces?

Yes. OTLP defines parallel services and endpoints for traces, metrics, and logs, with a shared resource model. One exporter configuration can send all three, but check which signals your backend actually stores.

Why do my spans arrive but look empty in the backend?

The transport worked, but the instrumentation did not attach the attributes the backend displays. For LLM applications, that usually means the spans lack OpenInference-style attributes such as inputs, outputs, and token counts. Fix the instrumentation layer, not the exporter.

Putting OTLP to work

When you set up OTLP export, record the endpoint, protocol, port, and which signals you send. Keep credentials in a secret store rather than in committed configuration.

Prove each layer before moving on: spans created locally, then transport, then ingestion. Arize Phoenix and Arize AX both document their OTLP endpoints and required headers, so start from those values rather than guessing.

Example

A Python agent instrumented with OpenInference creates spans, the OpenTelemetry SDK batches them, and the OTLP exporter sends them over gRPC to port 4317. If no trace appears, check span creation first, then whether the protocol matches the port (4317 for gRPC, 4318 for HTTP), then the required authorization headers.

Don’t ship vibes.

Arize gives AI teams observability and evals to understand and improve agent performance.