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

# OpenTelemetry

> Send OpenTelemetry traces to Sentrial when you already have OTel instrumentation or a collector pipeline.

Sentrial can ingest OpenTelemetry traces over OTLP HTTP JSON. Each trace becomes a Sentrial session, and each span becomes an event in the session timeline.

<Note>
  The current endpoint accepts OTLP HTTP JSON. OTLP protobuf is not enabled yet. If you use the
  OpenTelemetry Collector, set `encoding: json`.
</Note>

## When to Use OTel

Use this integration when:

* your agent framework already emits OpenTelemetry spans
* you have an existing OpenTelemetry Collector
* you want vendor-neutral tracing alongside Sentrial classification
* you are migrating gradually from another tracing tool

For new Sentrial-first integrations, use the native SDK instead.

<CardGroup cols={2}>
  <Card title="Native SDK" icon="code" href="/quickstart">
    Best for rich Sentrial sessions, prompt variants, costs, and wrappers.
  </Card>

  <Card title="Ingestion Options" icon="route" href="/concepts/ingestion-options">
    Compare the native SDK and OpenTelemetry paths.
  </Card>
</CardGroup>

## Endpoint

```txt theme={null}
POST https://api.sentrial.com/api/otel/v1/traces
```

Authenticate with either header:

```txt theme={null}
Authorization: Bearer sentrial_live_xxx
x-sentrial-api-key: sentrial_live_xxx
```

Your API key needs both `sessions:write` and `events:write` scopes.

## Collector Configuration

Forward traces from an OpenTelemetry Collector to Sentrial:

```yaml theme={null}
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 512
  batch:
    timeout: 1s
    send_batch_size: 100
    send_batch_max_size: 1000
  resource:
    attributes:
      - key: service.name
        value: my-agent
        action: upsert

exporters:
  otlphttp/sentrial:
    traces_endpoint: https://api.sentrial.com/api/otel/v1/traces
    encoding: json
    headers:
      x-sentrial-api-key: ${env:SENTRIAL_API_KEY}

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch, resource]
      exporters: [otlphttp/sentrial]
```

For local development with the API server on port `3001`, use:

```yaml theme={null}
exporters:
  otlphttp/sentrial:
    traces_endpoint: http://localhost:3001/api/otel/v1/traces
    encoding: json
    headers:
      x-sentrial-api-key: ${env:SENTRIAL_API_KEY}
```

## Recommended Attributes

Add these attributes to the root span when possible:

| Attribute                                | Purpose                                        |
| ---------------------------------------- | ---------------------------------------------- |
| `sentrial.agent.name`                    | Agent name in Sentrial                         |
| `sentrial.user_id` or `user.id`          | User grouping                                  |
| `sentrial.convo_id` or `conversation.id` | Conversation grouping                          |
| `sentrial.input`                         | Session input                                  |
| `sentrial.output`                        | Session output                                 |
| `sentrial.cost`                          | Estimated run cost                             |
| `sentrial.experiment.assignment_id`      | Links the trace to a prompt variant assignment |

Sentrial also maps common GenAI semantic convention attributes, including:

* `gen_ai.system`
* `gen_ai.request.model`
* `gen_ai.usage.input_tokens`
* `gen_ai.usage.output_tokens`
* `gen_ai.usage.total_tokens`
* `gen_ai.prompt`
* `gen_ai.completion`

## Minimal OTLP JSON Example

```bash theme={null}
curl -X POST https://api.sentrial.com/api/otel/v1/traces \
  -H "Content-Type: application/json" \
  -H "x-sentrial-api-key: sentrial_live_xxx" \
  -d '{
    "resourceSpans": [
      {
        "resource": {
          "attributes": [
            { "key": "service.name", "value": { "stringValue": "support-agent" } }
          ]
        },
        "scopeSpans": [
          {
            "spans": [
              {
                "traceId": "4fd0b6131f2f4ad9b4d05cc182b1fb11",
                "spanId": "9f3c4e3b8d9a1001",
                "name": "support request",
                "kind": "SPAN_KIND_SERVER",
                "startTimeUnixNano": "1770000000000000000",
                "endTimeUnixNano": "1770000002500000000",
                "attributes": [
                  { "key": "sentrial.agent.name", "value": { "stringValue": "support-agent" } },
                  { "key": "sentrial.user_id", "value": { "stringValue": "user_123" } },
                  { "key": "sentrial.convo_id", "value": { "stringValue": "conv_789" } },
                  { "key": "sentrial.input", "value": { "stringValue": "Help me reset my password" } },
                  { "key": "sentrial.output", "value": { "stringValue": "I sent a reset link." } },
                  { "key": "gen_ai.usage.input_tokens", "value": { "intValue": 1200 } },
                  { "key": "gen_ai.usage.output_tokens", "value": { "intValue": 300 } }
                ],
                "status": { "code": "STATUS_CODE_OK" }
              }
            ]
          }
        ]
      }
    ]
  }'
```

## Prompt Variants with OTel

OpenTelemetry ingestion does not choose prompt variants by itself. Route the variant first, then attach the assignment ID to your trace.

```typescript theme={null}
import { sentrial } from '@sentrial/sdk';

sentrial.configure({ apiKey: process.env.SENTRIAL_API_KEY! });

const assignment = await sentrial.getVariant({
  experimentName: 'support-prompt-v2',
  agentName: 'support-agent',
  userId: user.id,
  convoId: conversation.id,
});

const systemPrompt = assignment.systemPrompt ?? defaultSystemPrompt;
```

Add `assignment.assignmentId` to your root span as `sentrial.experiment.assignment_id`. Sentrial will link the ingested trace to that variant and classify the run after ingest.

## Classification

After Sentrial ingests a trace, it marks the session complete, stores span events, and runs the same signal classification pipeline used for SDK-created sessions.

## Next Steps

<CardGroup cols={2}>
  <Card title="Sessions" icon="timeline" href="/concepts/sessions">
    Learn how sessions and events appear in Sentrial.
  </Card>

  <Card title="Custom Integration" icon="code" href="/integrations/custom">
    Track custom agents with the native SDK.
  </Card>
</CardGroup>
