Documentation
OpenTelemetry
Send OpenTelemetry traces to Guardy when you already have OTel instrumentation or a collector pipeline.
Guardy can ingest OpenTelemetry traces over OTLP HTTP JSON. Each trace becomes a Guardy session, and each span becomes an event in the session timeline.
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 Guardy classification
- you are migrating gradually from another tracing tool
For new Guardy-first integrations, use the native SDK instead.
Best for rich Guardy sessions, prompt variants, costs, and wrappers.
Ingestion OptionsCompare the native SDK and OpenTelemetry paths.
Endpoint
POST https://api.tryguardy.com/api/otel/v1/tracesAuthenticate with either header:
Authorization: Bearer guardy_live_xxx
x-guardy-api-key: guardy_live_xxxYour API key needs both sessions:write and events:write scopes.
Collector Configuration
Forward traces from an OpenTelemetry Collector to Guardy:
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/guardy:
traces_endpoint: https://api.tryguardy.com/api/otel/v1/traces
encoding: json
headers:
x-guardy-api-key: ${env:GUARDY_API_KEY}
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch, resource]
exporters: [otlphttp/guardy]For local development with the API server on port 3001, use:
exporters:
otlphttp/guardy:
traces_endpoint: http://localhost:3001/api/otel/v1/traces
encoding: json
headers:
x-guardy-api-key: ${env:GUARDY_API_KEY}Recommended Attributes
Add these attributes to the root span when possible:
| Attribute | Purpose |
|---|---|
guardy.agent.name | Agent name in Guardy |
guardy.user_id or user.id | User grouping |
guardy.convo_id or conversation.id | Conversation grouping |
guardy.input | Session input |
guardy.output | Session output |
guardy.cost | Estimated run cost |
guardy.experiment.assignment_id | Links the trace to a prompt variant assignment |
Guardy also maps common GenAI semantic convention attributes, including:
gen_ai.systemgen_ai.request.modelgen_ai.usage.input_tokensgen_ai.usage.output_tokensgen_ai.usage.total_tokensgen_ai.promptgen_ai.completion
Minimal OTLP JSON Example
curl -X POST https://api.tryguardy.com/api/otel/v1/traces \
-H "Content-Type: application/json" \
-H "x-guardy-api-key: guardy_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": "guardy.agent.name", "value": { "stringValue": "support-agent" } },
{ "key": "guardy.user_id", "value": { "stringValue": "user_123" } },
{ "key": "guardy.convo_id", "value": { "stringValue": "conv_789" } },
{ "key": "guardy.input", "value": { "stringValue": "Help me reset my password" } },
{ "key": "guardy.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.
import { guardy } from '@guardy/sdk';
guardy.configure({ apiKey: process.env.GUARDY_API_KEY! });
const assignment = await guardy.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 guardy.experiment.assignment_id. Guardy will link the ingested trace to that variant and classify the run after ingest.
Classification
After Guardy ingests a trace, it marks the session complete, stores span events, and runs the same signal classification pipeline used for SDK-created sessions.