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

# OpenTelemetry

> Send OpenTelemetry traces to Adaline over OTLP/HTTP with minimal changes to your existing tracing setup.

# OpenTelemetry

Use OpenTelemetry when you already have tracing in place and want Adaline to ingest those spans with minimal application changes. Adaline accepts OTLP/HTTP traces, and the `@adaline/otel` / `adaline-otel` packages help route them to the Adaline OTEL ingestion endpoint.

This integration is best when your application is already instrumented with OpenTelemetry, either manually or through a framework that emits OpenTelemetry spans.

## Prerequisites

Before you start, make sure you have:

* An [Adaline account](https://app.adaline.ai/sign-up?utm_source=adaline.ai).
* A **workspace API key** — create one under **Settings → API keys**.
* Your **project ID** — copy it from **Monitor → Copy Project ID**.

See [Integrate your AI Agent](/docs/get-started/integrate-your-ai-agent) for a full walkthrough.

Set both as environment variables before running the examples on this page:

```bash theme={null}
export ADALINE_API_KEY="your-api-key"
export ADALINE_PROJECT_ID="your-project-id"
```

## Install

<Tabs>
  <Tab title="TypeScript">
    ```bash theme={null}
    npm install @adaline/otel @opentelemetry/api @opentelemetry/sdk-trace-base @opentelemetry/sdk-trace-node
    ```
  </Tab>

  <Tab title="Python">
    ```bash theme={null}
    pip install adaline-otel
    ```
  </Tab>
</Tabs>

## Configure routing and auth

Set your Adaline credentials in environment variables, then attach the Adaline exporter or span processor to your existing OpenTelemetry pipeline.

`ADALINE_API_KEY` is required in all cases.

Use one of the following routing values:

* `ADALINE_PROJECT_ID` when you want spans to land directly in a project
* `ADALINE_PARENT` when you want downstream services to attach spans to an existing Adaline parent

<CodeGroup>
  ```bash .env theme={null}
  ADALINE_API_KEY=your-api-key
  ADALINE_PROJECT_ID=your-project-id
  ADALINE_API_URL=https://api.adaline.ai
  ```

  ```bash .env theme={null}
  ADALINE_API_KEY=your-api-key
  ADALINE_PARENT=project_id:your-project-id
  ADALINE_API_URL=https://api.adaline.ai
  ```
</CodeGroup>

<Note>
  Set either `ADALINE_PROJECT_ID` or `ADALINE_PARENT`, but not conflicting values for both.
</Note>

<Note>
  For batching and flush tuning — interval, batch size, and queue limits — see [Configuration options](#configuration-options) below.
</Note>

## Choose an integration path

Use whichever path matches your current setup:

* `AdalineSpanProcessor` if you want Adaline to manage batching for spans exported from your tracer provider
* `AdalineExporter` if you already manage your own `BatchSpanProcessor` or exporter chain
* raw OTLP configuration if you want to point an existing collector/exporter directly at Adaline without using the package

## Configure the `AdalineSpanProcessor`

The application logic that creates spans does not need to change. You only need to add the Adaline span processor to the tracer provider you already use.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
    import { AdalineSpanProcessor } from "@adaline/otel";

    const provider = new NodeTracerProvider();

    provider.addSpanProcessor(
      new AdalineSpanProcessor({
        apiKey: process.env.ADALINE_API_KEY,
        projectId: process.env.ADALINE_PROJECT_ID,
      }),
    );

    provider.register();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os

    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.trace import set_tracer_provider

    from adaline_otel import AdalineOtelConfig, AdalineSpanProcessor

    provider = TracerProvider()
    provider.add_span_processor(
        AdalineSpanProcessor(
            AdalineOtelConfig(
                api_key=os.environ["ADALINE_API_KEY"],
                project_id=os.environ["ADALINE_PROJECT_ID"],
            )
        )
    )

    set_tracer_provider(provider)
    ```
  </Tab>
</Tabs>

## Configure the `AdalineExporter`

Use the exporter directly when you already manage your own batch processor and only want Adaline as the OTLP destination.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
    import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
    import { AdalineExporter } from "@adaline/otel";

    const provider = new NodeTracerProvider();

    provider.addSpanProcessor(
      new BatchSpanProcessor(
        new AdalineExporter({
          apiKey: process.env.ADALINE_API_KEY,
          projectId: process.env.ADALINE_PROJECT_ID,
        }),
      ),
    );

    provider.register();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os

    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    from opentelemetry.trace import set_tracer_provider

    from adaline_otel import AdalineExporter, AdalineOtelConfig

    provider = TracerProvider()
    provider.add_span_processor(
        BatchSpanProcessor(
            AdalineExporter(
                AdalineOtelConfig(
                    api_key=os.environ["ADALINE_API_KEY"],
                    project_id=os.environ["ADALINE_PROJECT_ID"],
                )
            )
        )
    )

    set_tracer_provider(provider)
    ```
  </Tab>
</Tabs>

## Send OTLP traces directly to Adaline

If you already have an OTLP HTTP exporter or collector in place, you can point it directly at Adaline without using the package helpers.

* endpoint: `https://api.adaline.ai/otel/v1/traces`
* required header: `Authorization: Bearer <ADALINE_API_KEY>`
* routing header: either `x-adaline-project-id: <PROJECT_ID>` or `x-adaline-parent: <PARENT>`

This is the same destination the Adaline OTel packages use internally.

## Basic example

This example stays intentionally small: one manually-created GenAI span with prompt and completion attributes. That is enough to validate the OTEL wiring without turning the docs into a full sample application.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import { trace } from "@opentelemetry/api";

    const tracer = trace.getTracer("adaline-otel-docs");

    await tracer.startActiveSpan("gen_ai.chat", async (modelSpan) => {
      modelSpan.setAttribute("gen_ai.system", "openai");
      modelSpan.setAttribute("gen_ai.operation.name", "chat");
      modelSpan.setAttribute("gen_ai.request.model", "gpt-4o-mini");
      modelSpan.setAttribute("gen_ai.prompt.0.role", "user");
      modelSpan.setAttribute("gen_ai.prompt.0.content", "Summarize the invoice.");
      modelSpan.setAttribute("gen_ai.completion.0.role", "assistant");
      modelSpan.setAttribute("gen_ai.completion.0.content", "Invoice inv_123 is marked as paid.");
      modelSpan.end();
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    from opentelemetry import trace

    tracer = trace.get_tracer("adaline-otel-docs")

    with tracer.start_as_current_span("gen_ai.chat") as model_span:
        model_span.set_attribute("gen_ai.system", "openai")
        model_span.set_attribute("gen_ai.operation.name", "chat")
        model_span.set_attribute("gen_ai.request.model", "gpt-4o-mini")
        model_span.set_attribute("gen_ai.prompt.0.role", "user")
        model_span.set_attribute("gen_ai.prompt.0.content", "Summarize the invoice.")

        model_span.set_attribute("gen_ai.completion.0.role", "assistant")
        model_span.set_attribute("gen_ai.completion.0.content", "Invoice inv_123 is marked as paid.")
    ```
  </Tab>
</Tabs>

The goal of this example is simply to confirm that your OpenTelemetry pipeline can export a GenAI-style span to Adaline successfully.

## Distributed tracing and multi-service workflows

If one service starts the trace and another service continues the work, create the Adaline parent once and propagate it downstream. Child services can recover that parent from incoming headers and attach new spans to the same trace.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import { addParentToBaggage, parentFromHeaders } from "@adaline/otel";

    const adalineParent = "project_id:your-project-id";
    const ctx = addParentToBaggage(adalineParent);

    // Pass standard OTEL headers plus baggage to downstream services.
    // On the receiving side:
    const parent = parentFromHeaders(request.headers);

    new AdalineSpanProcessor({
      apiKey: process.env.ADALINE_API_KEY,
      parent,
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    from adaline_otel import add_parent_to_baggage, parent_from_headers
    from adaline_otel import AdalineOtelConfig, AdalineSpanProcessor

    adaline_parent = "project_id:your-project-id"
    ctx = add_parent_to_baggage(adaline_parent)

    # Pass standard OTEL headers plus baggage to downstream services.
    # On the receiving side:
    parent = parent_from_headers(dict(request.headers))

    processor = AdalineSpanProcessor(
        AdalineOtelConfig(
            api_key=os.environ["ADALINE_API_KEY"],
            parent=parent,
        )
    )
    ```
  </Tab>
</Tabs>

Use this pattern when spans for a single agent run are produced across multiple workers, queue consumers, or services.

## AI span filtering

The Adaline OTel packages can optionally export only AI-related spans by setting `ADALINE_OTEL_FILTER_AI_SPANS=true`.

When that filter is enabled, the package keeps spans whose span name or attribute keys start with one of these prefixes:

* `gen_ai.`
* `adaline.`
* `llm.`
* `ai.`
* `traceloop.`

This behavior is implemented in the SDK packages directly. If you leave filtering disabled, all spans passed to the exporter are forwarded to Adaline.

## Configuration options

| Option                         | Description                                                                     |
| ------------------------------ | ------------------------------------------------------------------------------- |
| `ADALINE_API_KEY`              | Required. Authenticates OTLP exports to Adaline.                                |
| `ADALINE_API_URL`              | Optional. Defaults to `https://api.adaline.ai`.                                 |
| `ADALINE_PROJECT_ID`           | Routes spans into a project when no explicit parent is supplied.                |
| `ADALINE_PARENT`               | Routes spans to an existing Adaline parent for distributed tracing.             |
| `ADALINE_OTEL_FILTER_AI_SPANS` | When `true`, exports only spans identified as AI spans.                         |
| `ADALINE_OTEL_FLUSH_INTERVAL`  | Batch flush interval in seconds. Defaults to `5`.                               |
| `ADALINE_OTEL_MAX_BATCH_SIZE`  | Maximum number of spans per export batch. Defaults to `100`.                    |
| `ADALINE_OTEL_MAX_QUEUE_SIZE`  | Maximum in-memory queue size before flush pressure applies. Defaults to `1000`. |

## Supported span patterns

Adaline works best with AI-oriented OpenTelemetry spans, especially spans that already carry GenAI-style attributes. In practice, that means:

* spans with `gen_ai.*` attributes
* spans emitted by frameworks that already use OpenTelemetry for LLM, tool, or retrieval steps
* custom spans that you annotate yourself with AI-related attributes

This page intentionally focuses on transport and wiring. The exact trace shape you see in Adaline depends on the spans and attributes your instrumentation emits.

## Next steps

<CardGroup cols={2}>
  <Card title="Instrument with the Adaline SDK" icon="code" href="/docs/instrument/with-adaline-sdks">
    Monitor lifecycle, buffering and batching, retries, serverless flushing, and graceful shutdown.
  </Card>

  <Card title="SDK reference" icon="braces" href="/docs/reference/sdk/v2/overview">
    Full class and type reference for the TypeScript and Python SDKs.
  </Card>

  <Card title="All integrations" icon="layout-grid" href="/docs/integrations/introduction">
    Browse every framework and AI-provider integration Adaline supports.
  </Card>

  <Card title="View your logs" icon="line-chart" href="https://app.adaline.ai">
    Open Adaline to see traces and spans land in your project.
  </Card>
</CardGroup>
