Skip to content

OTLP Ingestion

xtrace supports OpenTelemetry Protocol (OTLP/HTTP) trace ingestion, making it compatible with any instrumentation that exports OTLP traces — including Langfuse's OpenTelemetry exporter.

Endpoint

POST /api/public/otel/v1/traces

Supported Formats

Content-TypeDescription
application/jsonJSON-encoded OTLP ExportTraceServiceRequest
application/x-protobufProtobuf-encoded OTLP ExportTraceServiceRequest

Gzip compression is supported via Content-Encoding: gzip.

Authentication

Both Bearer token and Basic auth are supported:

bash
# Bearer token
curl -X POST http://127.0.0.1:8742/api/public/otel/v1/traces \
  -H "Authorization: Bearer $API_BEARER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '...'

# Basic auth (Langfuse compatibility)
curl -X POST http://127.0.0.1:8742/api/public/otel/v1/traces \
  -u "$XTRACE_PUBLIC_KEY:$XTRACE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '...'

Attribute Mapping

xtrace extracts the following OTLP span attributes:

OTLP AttributeMaps To
traceId (16 bytes hex)trace.id (UUID)
spanId (8 bytes hex)observation.id (UUID, zero-padded)
parentSpanIdobservation.parentObservationId
nameobservation.name
startTimeUnixNanoobservation.startTime
endTimeUnixNanoobservation.endTime
langfuse.observation.typeobservation.type
langfuse.generation.modelobservation.model
gen_ai.request.modelobservation.model (fallback)
langfuse.observation.inputobservation.input
langfuse.observation.outputobservation.output
langfuse.observation.usage_detailsToken counts
langfuse.trace.nametrace.name
user.idtrace.userId
session.idtrace.sessionId
langfuse.trace.tagstrace.tags
langfuse.trace.metadata.*trace.metadata

Span Hierarchy

OTLP parent-child span relationships are preserved:

  • Spans with parentSpanId create nested observations
  • Root spans (no parent) become top-level observations
  • The span tree is reconstructed client-side using parentObservationId

This naturally supports agent workflow visualization:

Trace
  └─ Span: "P3 Cycle"
       ├─ Span: "Plan"    (parentSpanId = cycle)
       ├─ Span: "Execute"  (parentSpanId = cycle)
       │    └─ Span: "Tool Call"  (parentSpanId = execute)
       └─ Span: "Reflect"  (parentSpanId = cycle)

Usage with Langfuse Python SDK

python
import os
os.environ["LANGFUSE_HOST"] = "http://127.0.0.1:8742"
os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-xxx"
os.environ["LANGFUSE_SECRET_KEY"] = "sk-yyy"

from langfuse import Langfuse
langfuse = Langfuse()

trace = langfuse.trace(name="my-trace")
span = trace.span(name="agent-step")
generation = span.generation(
    name="llm-call",
    model="gpt-4",
    input=[{"role": "user", "content": "Hello"}],
    output="Hi there!",
)
langfuse.flush()

Released under the MIT License.