Skip to content

Backend Compatibility

By default Sema labels its telemetry with the OpenTelemetry GenAI semantic conventions — the standard gen_ai.* attribute names. Tools that follow that standard understand Sema's traces with no extra configuration.

A handful of popular LLM-observability tools don't read gen_ai.* — they look for their own attribute names instead, so a Sema span can show up in them as "unknown" or with blank fields. For those tools, set the SEMA_OTEL_COMPAT environment variable to a compatibility mode — a short name such as openinference or langfuse that tells Sema which extra attribute names to write alongside the standard ones. Nothing about your program changes — it's still the same automatic tracing, just labelled so more tools can read it.

This is purely additive: the standard gen_ai.* attributes are always present; SEMA_OTEL_COMPAT only adds extra copies under other names. Read the Tracing & Metrics page first for how tracing works and how to point Sema at a backend — this page only covers the per-tool labelling.

Which tools need a compatibility mode

This section covers the tools that can receive OpenTelemetry traces over OTLP. Most of them read the standard gen_ai.* attributes and need no compatibility mode; only a few key off their own attribute names and need a SEMA_OTEL_COMPAT mode. (Tools that ingest only through their own SDK, sit in front of your calls as a proxy, or run offline evaluations can't receive an OTLP push at all — see Tools you can't send traces to.)

"No compatibility mode" is not the same as "no setup."

Almost every hosted service still needs its own authentication header — an API key passed through OTEL_EXPORTER_OTLP_HEADERS, exactly as shown for Langfuse on the Tracing & Metrics page. That auth header is a property of the backend, not a Sema compatibility mode. The tables below say only whether a tool needs a SEMA_OTEL_COMPAT mode to understand Sema's attributes — the column for "does it need an API key" is "almost always, if it's hosted".

Reads gen_ai.* — no compatibility mode needed

General trace viewers and APM platforms. These store and display gen_ai.* as ordinary span attributes (the LLM-specific ones also build GenAI dashboards from them):

ToolSelf-hostable?Notes
Grafana / Tempo, Jaegeryesplain OpenTelemetry trace viewers
SigNozyesOTLP on 4317 / 4318
OpenObserveyesOTLP /api/{org}/v1/traces (verified live)
Honeycomb, Elasticpartlygeneral OTel APM
LogfirenoPydantic's OTel platform
Datadog LLM Observabilitynomaps gen_ai.* (semconv 1.37+) natively; needs a Datadog API-key header
Dynatracenomaps gen_ai.* natively; needs a Grail (DPS) licence + an ingest token
Coralogix AI Centernomaps gen_ai.*, but needs account-side setup (S3-archive routing + the experimental-semconv opt-in)
New Relicnoaccepts OTLP and stores gen_ai.* as raw attributes; native GenAI dashboards are not documented

LLM-native platforms. These parse gen_ai.* into structured LLM records on their own OTLP endpoint (all hosted ones need an API key/header):

ToolSelf-hostable?OTLP endpoint / notes
OpenLITyesOTel-native; docker compose up -d; OTLP on 4318, no auth by default
MLflowyestracking server exposes an OTLP /v1/traces endpoint
Braintrustnomaps gen_ai.* to structured fields; API key required (see the optional braintrust mode below)
W&B Weaveno…/otel/v1/traces; parses gen_ai.*; Basic-auth + project_id header (verified in docs)
Portkeyno/v1/otel/v1/traces; reads gen_ai.*; x-portkey-api-key header
HoneyHiveno/v1/traces; reads gen_ai.*; Bearer + x-honeyhive project header
Opik (Comet)yes/api/v1/private/otel (HTTP only); API key + project/workspace headers
Lunaryyes/v1/otel; reads gen_ai.*; Bearer token
Maxim AIno/v1/otel; reads gen_ai.* / llm.* / ai.*; x-maxim-* headers
PostHogyes/i/v0/ai/otel; maps gen_ai.*$ai_* events; project token
FutureAGInonative convention is gen_ai.* (+ fi.span.kind); OpenInference is only an optional output mode
Laminaryesparses gen_ai.* (+ its own lmnr.*); HTTP + gRPC; API key
Agentayestranslates gen_ai.* into its own ag.*; HTTP/protobuf only; API key
Confident AInoObservatory endpoint reads gen_ai.* (+ confident.*); API key — this is DeepEval's backend
Patronus AInoOTLP gRPC; ingests standard OTel spans; x-api-key header
Promptfoolocalbuilt-in OTLP receiver (port 4318) while promptfoo eval runs; no token

Needs a compatibility mode

These ingest OTLP but key off their own attribute names, so without the matching SEMA_OTEL_COMPAT mode a Sema span shows up with blank or "unknown" fields:

ToolSEMA_OTEL_COMPAT modeWhat it adds
Arize Phoenix, Arize AXopeninferencespan types, model/provider, tokens, cost, message I/O, tool args + schemas
Langfuselangfuseobservation type/model, usage + cost detail, trace-level input/output, tags
Traceloop / OpenLLMetrytraceloopspan types, entity input/output, indexed message keys, tool functions
LangSmithlangsmithrun types, session threading, tags/metadata
Braintrustbraintrust (optional)adds the richer braintrust.* tags/metadata/scores (it already reads gen_ai.* without it)

Often grouped with OpenLLMetry, but actually gen_ai.*-native: Laminar, LangWatch, Agenta and FutureAGI are sometimes listed as "Traceloop-compatible". In practice they read gen_ai.* directly (Agenta and FutureAGI translate it into their own namespace), so they need no compatibility mode — they're in the table above. The OpenLLMetry SDK works with them because it too emits gen_ai.*, not because they parse the traceloop.* namespace.

Advertise OTel but unconfirmed: Galileo, PromptLayer, Keywords AI, Arthur AI, and LangWatch accept OTLP or claim OpenTelemetry support, but their docs don't pin down which attributes they surface from a raw push. They may well work — send a trace with the standard setup and check whether your spans appear.

Setting SEMA_OTEL_COMPAT

It's an environment variable like the others (see How to turn it on). Its value is a comma-separated list of compatibility modes — the lower-case names from the table above:

bash
# Just Phoenix:
SEMA_OTEL_COMPAT=openinference sema myagent.sema

# Phoenix and Langfuse at once:
SEMA_OTEL_COMPAT=openinference,langfuse sema myagent.sema

# Every mode at once — useful if you're not sure which backend you'll use:
SEMA_OTEL_COMPAT=all sema myagent.sema

Accepted modes: openinference (also phoenix, arize), traceloop (also openllmetry), langsmith, langfuse, braintrust, and all. Names you don't recognise are ignored, so a typo won't break anything.

Some of the added detail — message text, tool arguments and results, and the trace-level input/output summary — is content, so it only appears when you also turn on content capture with OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true (see Privacy). Token counts, models, cost, and span types are always added.

When SEMA_OTEL_COMPAT is unset, no extra attributes are written — the traces are exactly what you get on the Tracing & Metrics page.

Per-tool setup

Arize Phoenix (OpenInference)

Phoenix is an open-source LLM trace viewer that runs in one container:

bash
# Start Phoenix. UI on 6006; it accepts traces on 6006 (HTTP) and 4317 (gRPC).
docker run -d --name phoenix -p 6006:6006 -p 4317:4317 arizephoenix/phoenix:latest

SEMA_OTEL_COMPAT=openinference \
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:6006 \
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true \
  sema -e '(llm/complete "say hi" {:max-tokens 16})'

Open http://localhost:6006. Each Sema span is typed (LLM / TOOL / AGENT / EMBEDDING) and shows the model, provider, token counts, cost, the message I/O, and — for agent runs — tool arguments, results, and the tool schemas offered to the model.

Langfuse

Langfuse already reads several of Sema's standard attributes (cost and message I/O). The langfuse value fills in the rest — the observation type and model, the usage/cost detail objects, and the trace-level input/output summary:

bash
SEMA_OTEL_COMPAT=langfuse \
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:3000/api/public/otel" \
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <base64 of publickey:secretkey>" \
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true \
  sema myagent.sema

(See the Langfuse example for how to build the auth header.) Multi-turn runs group into Sessions via the :session-id and :user-id options.

Traceloop (OpenLLMetry)

Traceloop is mainly a hosted product, but it reads plain OTLP, so you can also view the output in any OTLP backend (such as SigNoz). SEMA_OTEL_COMPAT=traceloop adds the traceloop.span.kind and traceloop.entity.* attributes, the indexed per-message keys, and the advertised tool functions. (You only need this for Traceloop's own platform — the look-alikes Laminar, LangWatch and Agenta read gen_ai.* directly.)

LangSmith

Point Sema at LangSmith's OTLP endpoint with your API key and SEMA_OTEL_COMPAT=langsmith; this adds LangSmith's run types, session threading, and tags/metadata, which are needed for those features (gen_ai.* alone can't populate them). LangSmith is primarily hosted, but Enterprise self-hosted deployments expose their own OTLP endpoint too.

Braintrust

Braintrust reads the standard attributes, so it works with no value set. Add braintrust only if you want its native braintrust.tags and braintrust.metadata fields.

Span-type mapping

How each Sema span is labelled for each tool when its compat value is on:

Sema spanOpenInferenceTraceloopLangSmithLangfuse
chatLLMtaskllmgeneration
embeddingsEMBEDDINGtaskembeddinggeneration
execute_toolTOOLtooltoolspan
invoke_agentAGENTagentchainspan
retrieve (vector search)RETRIEVERworkflowretrieverspan
rerankRERANKERworkflowchainspan
notebook cell / retryCHAINworkflowchainspan

Tags, metadata & streaming TTFT

With a compat mode on, three more things are filled in automatically — all behind the same SEMA_OTEL_COMPAT switch, so a plain OTel backend stays lean.

Auto-tags. Every LLM span is tagged with its operation:…, provider:…, and model:…, plus cache-hit on a cache-served response. These land on langfuse.trace.tags, braintrust.tags, and langsmith.span.tags.

Your own tags & metadata. Pass :tags (a list) and :metadata (a map) to llm/complete, llm/chat, llm/stream, or agent/run. Your tags are merged with the auto-tags; metadata fans out to each backend's native field (langfuse.trace.metadata.*, langsmith.metadata.*, traceloop.association.properties.*, braintrust.metadata).

sema
(llm/complete "Summarize this." {:max-tokens 100
                                 :tags ["prod" "summarizer"]
                                 :metadata {:env "prod" :feature "digest"}})

Streaming time-to-first-token. A streamed call records how long the first token took. It's always on the span as sema.gen_ai.server.time_to_first_token (seconds) + sema.gen_ai.is_streaming, and with compat on it also fills Langfuse's completion_start_time (which drives its TTFT column). Traceloop/OpenLLMetry gets the boolean gen_ai.is_streaming (OpenLLMetry has no per-span TTFT attribute — it tracks streaming latency as a histogram metric instead).

Two more identity fields ride along when their backend is active: LangSmith's langsmith.trace.session_id (it ignores the standard session.id), and Langfuse's langfuse.release from SEMA_OTEL_RELEASE.

Per-direction cost split (OpenInference). Alongside the combined llm.cost.total, chat spans also carry llm.cost.prompt and llm.cost.completion, so Phoenix/Arize show the prompt-vs-completion cost breakdown. Derived from Sema's in-SDK cost computation.

Embedding detail (OpenInference). Embeddings spans carry embedding.model_name, and — when content capture is enabled — the input texts at embedding.embeddings.{i}.embedding.text (capped per call). Raw vectors are never emitted.

Tools you can't send traces to

Some LLM tools collect data a different way — through their own client SDK, by sitting in front of your API calls as a proxy, or by running offline evaluations — rather than by receiving OpenTelemetry traces. Sema's OTLP export can't feed those; to use one, follow its own integration guide instead. The main categories:

  • Proxies / gateways — capture by routing your model calls through them, not by accepting traces: Helicone, LiteLLM, Pezzo. (Portkey is not here — its observability endpoint accepts OTLP and reads gen_ai.*; see the table above.)
  • SDK-only platforms — ingest only through their own Python/JS library, with no OTLP trace endpoint: Vellum, Athina AI, Parea AI, Nebuly.
  • Evaluation-only — offline scoring/testing, not a runtime trace receiver: RAGAS, UpTrain, Evidently AI, Giskard, TruLens.
  • Guardrails libraries that emit telemetry rather than receive it: NVIDIA NeMo Guardrails, Guardrails AI.
  • Has an OTLP endpoint, but needs attributes Sema doesn't emitFiddler AI accepts OTLP/HTTP, but requires its own fiddler.span.type and application.id on every span; without them spans are dropped, and Sema has no Fiddler compatibility mode to add them.

Several tools that used to be SDK-only or eval-only now run an OTLP endpoint — Opik, Lunary, PostHog, Maxim, Promptfoo, Patronus and Confident AI are all in the supported tables above. Humanloop is gone the other way: its team joined Anthropic and the platform was sunset in September 2025, so it's no longer an integration target. If a tool below later adds an OTLP endpoint that reads the GenAI conventions, Sema works with it the same as the others — no change needed on Sema's side.

Limitations

  • Message content requires the opt-in flag. The message I/O, tool arguments and results, and the trace-level input/output only appear when OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true. Token counts, models, cost, and span types are always added.
  • OpenInference has no separate tool-result field — the result appears in the tool span's output.value rather than a dedicated attribute.
  • A backend may re-derive cost from the token counts on its side rather than reading Sema's gen_ai.usage.cost, so the figure it shows can differ from Sema's exact per-call cost (which accounts for cache pricing).
  • Proxies and gateways can't receive traces. Helicone, LiteLLM and Pezzo capture data by routing your model calls through them, not by accepting an OTLP push — use their own integration instead.
  • Not yet implemented: the per-message indexed attribute form some older Traceloop/LangSmith parsers expect (Sema emits the structured and entity forms today).
  • More attributes per span. Compat adds extra copies of each value. If you only use a plain OTel backend, leave SEMA_OTEL_COMPAT unset to keep spans lean.