Reporting telemetry from an external agent

Use this guide to send telemetry from an agent that runs outside Runtype. You can use Flue, LangChain, the Vercel AI SDK, or your own agent loop. If your agent emits OpenTelemetry data, configure the exporter without a Runtype SDK.

Runtype stores the imported data as external executions. Your agent keeps using its existing model provider and credentials. Runtype does not run the agent or bill the imported run as a Runtype execution.

Create a telemetry API key

Create a dedicated API key for telemetry. On the dashboard API Keys page, select Telemetry Ingest. The permission group grants one scope: TELEMETRY:WRITE.

Use a dedicated key because the key can appear in collector configuration, container environments, and other shared locations. Ingest only appends data, so the key does not need read or management permissions.

The API does not let one API key create another API key. Create the telemetry key in the dashboard, then store it in the exporter configuration.

Existing keys with AGENTS:WRITE continue to work with the ingest endpoints.

Configure the OTLP/HTTP exporter

Set one base endpoint and identify the Runtype agent that receives the runs:

Environment variables
$OTEL_EXPORTER_OTLP_ENDPOINT=https://api.runtype.com/v1/otel
$OTEL_EXPORTER_OTLP_HEADERS=authorization=Bearer rt_YOUR_API_KEY,x-runtype-agent-id=agent_YOUR_AGENT_ID

Replace rt_YOUR_API_KEY with the telemetry API key. Replace agent_YOUR_AGENT_ID with the ID of the Runtype agent that receives the runs.

OpenTelemetry appends /v1/traces, /v1/metrics, and /v1/logs to the base endpoint for each signal. A single endpoint therefore configures all three signals.

Create the agent in the dashboard before you send telemetry. Runtype displays runs per agent.

Runtype accepts OTLP over HTTP, not OTLP over gRPC. If your SDK defaults to gRPC, set the HTTP protocol:

Use when the SDK defaults to gRPC
$OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

Restart the agent. The next exported run appears in the Runs view.

Configure the exporter in code

If your application builds the OpenTelemetry pipeline in code, configure the trace exporter with the same endpoint.

For a Node.js application, use the following TypeScript configuration:

TypeScript SDK
1import { NodeSDK } from '@opentelemetry/sdk-node'
2import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'
3
4const sdk = new NodeSDK({
5 traceExporter: new OTLPTraceExporter({
6 url: 'https://api.runtype.com/v1/otel/v1/traces',
7 headers: {
8 authorization: `Bearer ${process.env.RUNTYPE_API_KEY}`,
9 'x-runtype-agent-id': 'agent_YOUR_AGENT_ID',
10 },
11 }),
12})
13sdk.start()

Replace agent_YOUR_AGENT_ID with the ID of the Runtype agent that receives the runs.

For a Python application, configure the HTTP trace exporter as follows:

Python SDK
1import os
2
3from opentelemetry import trace
4from opentelemetry.sdk.trace import TracerProvider
5from opentelemetry.sdk.trace.export import BatchSpanProcessor
6from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
7
8exporter = OTLPSpanExporter(
9 endpoint="https://api.runtype.com/v1/otel/v1/traces",
10 headers={
11 "authorization": f"Bearer {os.environ['RUNTYPE_API_KEY']}",
12 "x-runtype-agent-id": "agent_YOUR_AGENT_ID",
13 },
14)
15provider = TracerProvider()
16provider.add_span_processor(BatchSpanProcessor(exporter))
17trace.set_tracer_provider(provider)

Replace agent_YOUR_AGENT_ID with the ID of the Runtype agent that receives the runs.

Use this cURL request to verify the endpoint, API key, and content type with an empty OTLP/JSON export:

cURL smoke test
$curl -X POST https://api.runtype.com/v1/otel/v1/traces \
> -H "Authorization: Bearer $RUNTYPE_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"resourceSpans": []}'

Set RUNTYPE_API_KEY to the telemetry API key before you run the command. The endpoint returns HTTP 200 with {} when it accepts the empty export.

For Python, install opentelemetry-exporter-otlp-proto-http. The Python gRPC exporter is the default, so select the HTTP exporter or set OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf.

Send several services through one collector

If an OpenTelemetry Collector exports several instrumented services in one request, identify each service with a resource attribute:

Per-service attribution
$OTEL_RESOURCE_ATTRIBUTES=runtype.agent.id=agent_YOUR_AGENT_ID

Replace agent_YOUR_AGENT_ID with the ID of the Runtype agent for that service.

For each trace, Runtype resolves the agent from the resource attribute first, then the x-runtype-agent-id header, and then the runtype.agent.id attribute on the invoke_agent span. The header provides the fallback for traces that do not set the resource attribute.

Run several agents in one process

If one process runs several agents, set runtype.agent.id on the invoke_agent span that opens each run:

Per-run attribution
1span.setAttribute('runtype.agent.id', 'agent_YOUR_AGENT_ID')

Replace agent_YOUR_AGENT_ID with the ID of the agent for that run.

The resource attribute and header describe a process or export. The span attribute identifies a run when one process uses a shared resource for several agents.

If two invoke_agent spans claim different agents and neither the resource attribute nor the header identifies the agent, Runtype rejects the trace as ambiguous_agent_attribution. One trace represents one run. If agents delegate inside one trace, set attribution at the resource or header level, or export each invocation as a separate trace.

Runtype resolves attribution per trace. If some traces name an agent that your key cannot use, Runtype stores the accepted traces and reports the rejected traces as OTLP partial_success. If no trace is accepted, the endpoint returns an error. Accepted traces do not return an error, so the exporter does not resend them because another trace in the export was rejected.

Understand imported telemetry

Runtype projects traces into external executions and eval capture. It retains spans and span events in Logs. It also retains attributed OTLP LogRecord data and links it to an execution when it includes a trace ID.

Runtype acknowledges metrics but does not store them. This lets a stock exporter use the same base endpoint without retrying a missing signal endpoint.

OTLP delivery can repeat an export. Runtype stores received rows as append-only data and deduplicates retry records when it displays Logs and trace trees. Span events remain separate. Repeated byte-identical LogRecord entries converge to one displayed record.

Runtype requires agent attribution to store OTLP LogRecord data. Without runtype.agent.id on the Logs resource or the x-runtype-agent-id header, Runtype returns OTLP partial_success and does not store those records. Add one of these attribution methods to make the records visible.

After attribution, Runtype stores LogRecord bodies and attributes under the target agent’s logging policy. Set that policy to Off before enabling the Logs signal if you do not want to retain application logs. Enable personally identifiable information (PII) redaction when the payloads can contain personal data.

Runtype derives the run, tool calls, token counts, and a cost estimate from the traces. It calculates the display-only cost with the Runtype model catalog. Your provider charges you for the model calls, so treat the cost as an estimate.

To capture conversation content, set the generative AI (GenAI) content attributes on your spans. Runtype maps them to the run as follows:

AttributeResult
gen_ai.input.messagesThe run’s transcript.
gen_ai.system_instructionsThe transcript’s system turn.
gen_ai.output.messagesThe run’s final output.
gen_ai.tool.call.argumentsA tool call’s input parameters.
gen_ai.tool.call.resultA tool call’s result.

Some instrumentations use different attribute names when content is not a plain JSON object. Runtype also recognizes flue.tool.call.arguments and flue.tool.call.result from @flue/opentelemetry. This support preserves tool results that are arrays or strings. If a span carries both names, Runtype uses the standard attribute. Runtype applies the same scrubbing and size limits to an aliased value.

If you use Flue, the first-party @runtypelabs/flue-otel instrumentation reports an exact loop iteration count, a stop reason, and rolled-up usage. See Instrumenting a Flue agent. The package sends no content, so it does not provide transcript or eval capture.

Point exactly one Flue instrumentation package at a Runtype endpoint. If you export with both @runtypelabs/flue-otel and @flue/opentelemetry, Runtype receives two invoke_agent spans for one run. The reported token counts and cost then double.

Content capture is opt-in. If you omit the GenAI content attributes, Runtype displays the execution structure and cost without conversation content. Before you enable content capture, account for these limits:

  • Scrubbing and size limits. Runtype redacts credential-shaped strings before storage. It drops a content attribute over 256 KiB, content that exceeds the 384 KiB per-span budget, or content beyond the 2 MiB export budget. Runtype drops each affected value whole instead of truncating it.
  • Partial-trace fidelity. Runtype records the fidelity that each run achieves. This distinguishes an empty model response from content that the exporter omits.

Use compatibility ingest without OpenTelemetry

To send unified execution events without OpenTelemetry, post a batch to the compatibility endpoint:

Direct ingest
$curl -X POST https://api.runtype.com/v1/executions/ingest \
> -H "Authorization: Bearer rt_YOUR_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "executionId": "YOUR_EXECUTION_ID",
> "agentId": "agent_YOUR_AGENT_ID",
> "events": [
> {
> "type": "execution_start",
> "executionId": "YOUR_EXECUTION_ID",
> "seq": 0,
> "kind": "agent",
> "startedAt": "2026-01-01T00:00:00Z"
> },
> {
> "type": "execution_complete",
> "executionId": "YOUR_EXECUTION_ID",
> "seq": 1,
> "kind": "agent",
> "success": true
> }
> ]
> }'

Replace rt_YOUR_API_KEY with the telemetry API key. Replace agent_YOUR_AGENT_ID with the ID of the target Runtype agent. Replace YOUR_EXECUTION_ID with a unique ID for the run.

The request body contains a batch from the unified execution event vocabulary. The endpoint accepts the same TELEMETRY:WRITE key and populates the agent’s Runs view and eval capture, including the transcript when the events carry it. For the event schema, see the API Reference.

This endpoint does not retain the structural span and span-event records that Logs and trace_execution use. On these runs, trace_execution reports json_ingest_compatibility_path as the availability reason. Use the OTLP/HTTP endpoints when you need Logs, parent-child trace trees, or OTLP LogRecord data. Use compatibility ingest when Runs and eval capture meet your needs.

Next steps

Continue with one of these guides: