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

# OpenTelemetry (OTel)

> Send traces from any OTel-instrumented AI framework directly to Agnost AI

Agnost AI runs a hosted OTLP collector at `otel.agnost.ai`. Any framework that emits OpenTelemetry spans can ship them straight to Agnost: no SDK required.

```
Your AI App  →  otel.agnost.ai  →  Agnost Dashboard
```

## Quick Setup

Set two environment variables before starting your app:

```bash theme={null}
OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.agnost.ai
OTEL_EXPORTER_OTLP_HEADERS="X-Agnost-Org-ID=<your-org-id>"
```

Get your org ID from [app.agnost.ai](https://app.agnost.ai).

For SDKs that take an explicit URL, use `https://otel.agnost.ai/v1/traces`.

## Custom Tool Spans

If your stack doesn't have a framework integration, wrap each agent / tool call in an OTel span. Name the span with a `tool.` prefix so Agnost classifies it as a tool call.

### 1. Install

**Already have an OTel SDK and the OTLP exporter installed?** Skip.

**No OTel yet?**

<CodeGroup>
  ```bash Python theme={null}
  pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
  ```

  ```bash TypeScript theme={null}
  npm install @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-proto @opentelemetry/api
  ```
</CodeGroup>

### 2. Wire the OTLP exporter pointing at Agnost

**Already have an OTel TracerProvider?** Append Agnost as an additional span processor:

<CodeGroup>
  ```python Python theme={null}
  from opentelemetry import trace
  from opentelemetry.sdk.trace.export import BatchSpanProcessor
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

  trace.get_tracer_provider().add_span_processor(
      BatchSpanProcessor(
          OTLPSpanExporter(
              endpoint="https://otel.agnost.ai/v1/traces",
              headers={"X-Agnost-Org-ID": os.environ["AGNOST_ORG_ID"]},
          )
      )
  )
  ```

  ```typescript TypeScript theme={null}
  import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
  import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';

  provider.addSpanProcessor(
    new BatchSpanProcessor(
      new OTLPTraceExporter({
        url: 'https://otel.agnost.ai/v1/traces',
        headers: { 'X-Agnost-Org-ID': process.env.AGNOST_ORG_ID! },
      }),
    ),
  );
  ```
</CodeGroup>

**No OTel yet?** Full setup:

<CodeGroup>
  ```python Python theme={null}
  import os
  from opentelemetry import trace
  from opentelemetry.sdk.trace import TracerProvider
  from opentelemetry.sdk.trace.export import BatchSpanProcessor
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
  from opentelemetry.sdk.resources import Resource

  provider = TracerProvider(resource=Resource.create({"service.name": "my-app"}))
  provider.add_span_processor(
      BatchSpanProcessor(
          OTLPSpanExporter(
              endpoint="https://otel.agnost.ai/v1/traces",
              headers={"X-Agnost-Org-ID": os.environ["AGNOST_ORG_ID"]},
          )
      )
  )
  trace.set_tracer_provider(provider)
  ```

  ```typescript TypeScript theme={null}
  import { NodeSDK } from '@opentelemetry/sdk-node';
  import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';

  new NodeSDK({
    traceExporter: new OTLPTraceExporter({
      url: 'https://otel.agnost.ai/v1/traces',
      headers: { 'X-Agnost-Org-ID': process.env.AGNOST_ORG_ID! },
    }),
  }).start();
  ```
</CodeGroup>

### 3. Wrap each agent turn in a span with userId / sessionId

<CodeGroup>
  ```python Python theme={null}
  tracer = trace.get_tracer(__name__)

  with tracer.start_as_current_span("tool.search_web") as span:
      span.set_attribute("agnost.user_id", "user-42")
      span.set_attribute("agnost.session_id", "conv-abc123")
      span.set_attribute("input", query)
      try:
          result = search_web(query)
          span.set_attribute("output", str(result))
      except Exception as exc:
          span.record_exception(exc)
          raise
  ```

  ```typescript TypeScript theme={null}
  import { trace, SpanStatusCode } from '@opentelemetry/api';

  const tracer = trace.getTracer('my-app');

  const span = tracer.startSpan('tool.search_web');
  span.setAttribute('agnost.user_id', 'user-42');
  span.setAttribute('agnost.session_id', 'conv-abc123');
  span.setAttribute('input', query);
  try {
    const result = await searchWeb(query);
    span.setAttribute('output', JSON.stringify(result));
  } catch (err) {
    span.setStatus({ code: SpanStatusCode.ERROR });
    throw err;
  } finally {
    span.end();
  }
  ```
</CodeGroup>
