> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://www.comet.com/docs/opik/integrations/opentelemetry/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://www.comet.com/_mcp/server. # OpenTelemetry # Get Started with OpenTelemetry Opik provides native support for OpenTelemetry (OTel), allowing you to instrument your ML/AI applications with distributed tracing. This guide will show you how to directly integrate OpenTelemetry SDKs with Opik. > **Note** > > OpenTelemetry integration in Opik currently supports HTTP transport. We're actively working on expanding the feature > set - stay tuned for updates! ## OpenTelemetry Endpoint Configuration ### Base Endpoint To start sending traces to Opik, configure your OpenTelemetry exporter with one of these endpoints: #### Opik Cloud ```bash wordWrap export OTEL_EXPORTER_OTLP_ENDPOINT="https://www.comet.com/opik/api/v1/private/otel" export OTEL_EXPORTER_OTLP_HEADERS="Authorization=,projectName=,Comet-Workspace=" ``` #### Self-hosted deployment ```bash wordWrap export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:5173/api/v1/private/otel" ``` #### Enterprise deployment ```bash wordWrap export OTEL_EXPORTER_OTLP_ENDPOINT="https:///opik/api/v1/private/otel" export OTEL_EXPORTER_OTLP_HEADERS="Authorization=,projectName=,Comet-Workspace=" ``` ### Signal-Specific Endpoint If your OpenTelemetry setup requires signal-specific configuration, you can use the traces endpoint. This is particularly useful when different signals (traces, metrics, logs) need to be sent to different endpoints: ```bash wordWrap export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="http:///api/v1/private/otel/v1/traces" ``` ## Custom via OpenTelemetry SDKs You can use any OpenTelemetry SDK to send traces directly to Opik. OpenTelemetry provides SDKs for many languages (C++, .NET, Erlang/Elixir, Go, Java, JavaScript, PHP, Python, Ruby, Rust, Swift). This extends Opik's language support beyond the official SDKs (Python and TypeScript). For more instructions, visit the [OpenTelemetry documentation](https://opentelemetry.io/docs/languages/). Here's a Python example showing how to set up OpenTelemetry with Opik: ```python wordWrap from opentelemetry import trace from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( OTLPSpanExporter ) from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor # For Comet-hosted installations OPIK_ENDPOINT = "https:///api/v1/private/otel/v1/traces" API_KEY = "" PROJECT_NAME = "" WORKSPACE_NAME = "" # Initialize the trace provider provider = TracerProvider() processor = BatchSpanProcessor( OTLPSpanExporter( endpoint=OPIK_ENDPOINT, headers={ "Authorization": API_KEY, "projectName": PROJECT_NAME, "Comet-Workspace": WORKSPACE_NAME } ) ) provider.add_span_processor(processor) trace.set_tracer_provider(provider) ``` > **Tip** > > In order to track OpenAI calls, you need to use the OpenTelemetry instrumentations > for OpenAI: > > ```bash wordWrap > pip install opentelemetry-instrumentation-openai > ``` > > And then instrument your OpenAI client: > > ```python wordWrap > from opentelemetry.instrumentation.openai import OpenAIInstrumentor > > OpenAIInstrumentor().instrument() > ``` > **Warning** > > Make sure to import the `http` trace exporter (`opentelemetry.exporter.otlp.proto.http.trace_exporter`), if you use > the GRPC exporter you will face errors. ## Opik-specific span attributes Opik reads a small set of span attributes and maps them to Opik fields. Set them with the standard OpenTelemetry API on any span. | Attribute | Effect | | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | | `opik.tags` | Adds tags to the span. On the root span, Opik also adds the tags to the trace, so you can filter your traces by tag. | | `opik.metadata.` | Adds `` to the metadata of the span. The metadata of the root span also becomes the metadata of the trace. | | `thread_id` | Groups traces into one conversational thread. See [Multi-turn conversations](/evaluation/evaluate_threads). | | `opik.trace_id`, `opik.parent_span_id`, `opik.span_id` | Attaches the span to an Opik trace and parent span that already exist. See [Distributed traces](/tracing/advanced/log_distributed_traces). | ### Tagging traces and spans Opik accepts three formats for the `opik.tags` attribute: * A list of strings: `["production", "chatbot"]` * A JSON array in a string: `'["production", "chatbot"]'` * A comma-separated string: `"production,chatbot"` ```python wordWrap with tracer.start_as_current_span("chatbot_conversation") as conversation_span: # The root span carries the tags, so the trace carries them too conversation_span.set_attribute("opik.tags", ["production", "chatbot"]) conversation_span.set_attribute("opik.metadata.environment", "staging") with tracer.start_as_current_span("llm_completion") as llm_span: # A child span carries the tags on the span only llm_span.set_attribute("opik.tags", ["llm-call"]) ``` > **Note** > > Set `opik.tags` on the root span if you want to filter traces by tag. Tags on a child span apply to that span only. > Debug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.