Tracing (OpenTelemetry / OTLP)

Enprompta exposes a standard OTLP/HTTP trace endpoint. Any OpenTelemetry SDK, OpenInference, or OpenLLMetry exporter can send traces with no custom code — just point your existing instrumentation at Enprompta with two environment variables.

On Node or Python? The Enprompta SDK auto-instruments OpenAI, Anthropic & Gemini in one line — see the TypeScript or Python SDK docs. This page is the vendor-neutral OTLP reference for everything else.

Instrument with a coding agent

On a Node or Python app, the fastest way to start reporting traces is to let your coding agent wire it up. Enprompta ships an open Agent Skill (the standard supported by Claude Code, Cursor, Codex, Copilot, Gemini CLI, and others) that instruments your app end to end — detect the stack (language, provider, framework, entrypoint), install the SDK, wire auto-instrumentation at the entrypoint, and verify a real trace lands.

Tracing is fail-silent by design — it never throws, so a broken setup produces no error, just no traces. The skill treats “done” as a trace you can actually see, and won't stop until it confirms one arrived.

Add the skill to your agent, set your key, then ask it to set up tracing:

Terminal
# 1. Add the skill to your agent (any Skills-compatible agent).
npx skills add enprompta/enprompta-skills --skill enprompta-instrumentation

# 2. Set your key — from the dashboard → API Keys.
#    The agent references the env var; it never handles the value.
export ENPROMPTA_API_KEY=ep_your_api_key

# 3. Prompt your agent:
#    "Set up Enprompta tracing in my app."

The skill handles the sharp edges that make setup silently no-op — ESM module patching, running init() before the provider is imported, and framework span-trees for LangChain / LlamaIndex. Prefer to wire it by hand? See the TypeScript or Python SDK guides, or the vendor-neutral OTLP reference below.

No shell, or want the check as a tool? The @enprompta/mcp-server exposes a verify_setup tool (and trace/eval tools) to any MCP-capable agent — so the agent confirms a real trace landed without leaving the conversation.

1. Endpoint & authentication

The OTLP/HTTP trace endpoint accepts the standard OTLP /v1/traces path:

Endpoint
POST https://enprompta.com/api/ingest/otlp/v1/traces

Authenticate with an API key sent as a Bearer token. The key must have the traces:write scope — create one in your dashboard under API Keys.

Authorization header
Authorization: Bearer ep_your_api_key

Both OTLP wire formats are supported: application/x-protobuf (the OTLP default) and application/json.

2. Quick start (any OTel exporter)

If you already use OpenTelemetry — directly, or via OpenInference or OpenLLMetry auto-instrumentation — you don't need an Enprompta SDK. Set the two standard OTLP environment variables and your traces flow to Enprompta:

Environment variables
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://enprompta.com/api/ingest/otlp/v1/traces"
OTEL_EXPORTER_OTLP_TRACES_HEADERS="Authorization=Bearer ep_your_api_key"

That's it — any instrumentation that emits the OpenInference (llm.*) or OpenTelemetry GenAI (gen_ai.*) semantic conventions is understood automatically (see section 4).

For example, with the Python OpenTelemetry SDK the standard OTLP HTTP exporter picks those variables up:

Python (OpenTelemetry SDK)
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

provider = TracerProvider()
# Reads OTEL_EXPORTER_OTLP_TRACES_ENDPOINT and _HEADERS from the environment
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))

# Now add your LLM instrumentation (OpenInference / OpenLLMetry) as usual —
# its spans are exported straight to Enprompta.

Prefer not to wire up OTLP? The Enprompta SDK ships an ergonomic span-tree builder — enprompta.trace().span().end() — that produces the same typed, session-grouped span trees from plain app code (bundler-safe, no exporter setup). Ideal for agents and tool loops. See the TypeScript SDK guide.

Bring your own OpenInference / OpenLLMetry

Already running OpenInference (Arize) or OpenLLMetry (Traceloop) instrumentation — or migrating from Phoenix / LangSmith / Langfuse? You don't switch libraries. Keep your instrumentation and point its OTLP exporter at Enprompta. Two ways:

Environment variables (most exporters)

Traceloop/OpenLLMetry and most OpenTelemetry exporters read the standard OTLP variables — the same two from section 2:

Environment variables
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://enprompta.com/api/ingest/otlp/v1/traces"
OTEL_EXPORTER_OTLP_TRACES_HEADERS="Authorization=Bearer ep_your_api_key"

In code — Python (OpenInference + OTel SDK)

Configure the exporter with Enprompta's endpoint and Bearer header, then register your instrumentor as usual:

Python
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(
    endpoint="https://enprompta.com/api/ingest/otlp/v1/traces",
    headers={"Authorization": "Bearer ep_your_api_key"},
)))

# Then register your OpenInference instrumentor against this provider, e.g.:
# from openinference.instrumentation.openai import OpenAIInstrumentor
# OpenAIInstrumentor().instrument(tracer_provider=provider)

In code — TypeScript (SDK helper)

The Enprompta SDK ships otlpExporterConfig(), so you don't hand-write the endpoint or header:

TypeScript
import { otlpExporterConfig } from '@enprompta/sdk'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'

const exporter = new OTLPTraceExporter(
  otlpExporterConfig({ apiKey: process.env.ENPROMPTA_API_KEY! }),
)
// register `exporter` on your TracerProvider as usual

Both conventions are understood on ingest (see section 4), and cost is priced from the model when the span omits it. To confirm it worked, watch Observability — or have your coding agent run the MCP verify_setup tool.

3. Send a trace with cURL

A minimal OTLP/JSON request — useful to verify connectivity. IDs are hex strings and timestamps are unix nanoseconds:

OTLP/JSON via cURL
curl -X POST https://enprompta.com/api/ingest/otlp/v1/traces \
  -H "Authorization: Bearer ep_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "resourceSpans": [{
      "resource": { "attributes": [
        { "key": "enprompta.environment", "value": { "stringValue": "production" } }
      ]},
      "scopeSpans": [{
        "spans": [{
          "traceId": "5b8efff798038103d269b633813fc60c",
          "spanId": "eee19b7ec3c1b174",
          "name": "chat",
          "startTimeUnixNano": "1700000000000000000",
          "endTimeUnixNano": "1700000001200000000",
          "status": { "code": 1 },
          "attributes": [
            { "key": "gen_ai.system", "value": { "stringValue": "openai" } },
            { "key": "gen_ai.request.model", "value": { "stringValue": "gpt-4o" } },
            { "key": "gen_ai.prompt", "value": { "stringValue": "Summarise this ticket." } },
            { "key": "gen_ai.completion", "value": { "stringValue": "The customer reports..." } },
            { "key": "gen_ai.usage.prompt_tokens", "value": { "intValue": 120 } },
            { "key": "gen_ai.usage.completion_tokens", "value": { "intValue": 48 } }
          ]
        }]
      }]
    }]
  }'

On success the endpoint returns 200 with an OTLP ExportTraceServiceResponse (an empty partialSuccess object). Spans are persisted asynchronously and appear under Observability.

4. Semantic conventions

Enprompta reads span attributes from both the OpenInference (llm.*) and OpenTelemetry GenAI (gen_ai.*) conventions. Provide either; if both are present, llm.* wins.

FieldOpenInferenceOpenTelemetry GenAI
Providerllm.providergen_ai.system
Modelllm.modelgen_ai.request.model
Input / promptllm.input.messagesgen_ai.prompt
Output / completionllm.output.messagesgen_ai.completion
Input tokensllm.token_count.promptgen_ai.usage.prompt_tokens
Output tokensllm.token_count.completiongen_ai.usage.completion_tokens
Latency (ms)llm.latency_ms— (else derived from span start/end)
Costllm.cost— (else priced from model)

Cost & latency are filled in for you. If a span omits llm.cost, Enprompta prices it from the provider/model. If it omits llm.latency_ms, latency is derived from the span's start and end times. Any attribute not in the table above is kept on the trace as metadata.

5. Linking prompts, sessions & environments

Set these enprompta.* span (or resource) attributes to connect a trace to the rest of your workspace:

AttributePurpose
enprompta.environmentEnvironment label (defaults to "production").
enprompta.prompt_idLink the trace to a registered prompt.
enprompta.prompt_version_idLink to a specific prompt version.
enprompta.session_id (or session.id)Group multi-turn calls into one session.
enprompta.project_idAssign the trace to a project.

Resource-level attributes are inherited by every span in the batch (span-level values override them) — so set enprompta.environment and enprompta.project_id once on the resource.

6. Quotas, limits & responses

  • Monthly trace quota. Free includes 5,000 traces/month; Pro 200,000. Over quota, the endpoint returns 403 with a partialSuccess.rejectedSpans count — a permanent (non-retryable) signal per the OTLP spec, so exporters drop the batch rather than retry.
  • Batch size. Up to 100 spans are accepted per request. If a batch exceeds that, the extra spans are reported in partialSuccess.rejectedSpans; send larger volumes across multiple batches.
  • Errors. A span with OTLP status code ERROR is recorded as a failed trace (its status message is preserved).
  • Auth failures. A missing, invalid, or expired key returns 401; a valid key that lacks the traces:write scope returns 403.

Prefer a managed client? The Python and TypeScript SDKs can also send traces via the native /api/v1/traces endpoint.

Tracing (OpenTelemetry / OTLP) - Enprompta