OTLP export
Export traces as OpenTelemetry spans for your existing observability stack.
Reach for OTLP export when you want a stitch's events as OpenTelemetry spans in the observability stack you already run — each call's event stream maps to one CLIENT span, so a stitch drops into your existing OTel collector with no new plumbing. It is just another trace sink, teed alongside the console/JSONL sink rather than replacing it.
Example
The zero-code path is an env toggle: set STITCH_EXPORT=otlp and every stitch
also fans its events to an OTLP collector (default
http://localhost:4318/v1/traces, or OTEL_EXPORTER_OTLP_ENDPOINT).
STITCH_EXPORT=otlp OTEL_EXPORTER_OTLP_ENDPOINT=https://api.example.com node app.jsTo wire it yourself — to set headers, or to tee OTLP next to your own sink —
build the sink with otlpSink() and combine sinks with multiplex:
import { , , } from 'stitchapi';
const = (
({ : true }),
({
: 'https://api.example.com',
: { : 'Bearer token' },
}),
);Options
STITCH_EXPORT=otlp is the toggle (a comma list, e.g. console,otlp);
OTEL_EXPORTER_OTLP_ENDPOINT sets the collector base URL.
otlpSink(opts?) returns a sink. OtlpOptions carries endpoint (OTLP/HTTP
base URL), headers (extra headers on the POST, e.g. auth), and exporter (a
custom SpanExporter destination, defaulting to the built-in HTTP exporter).
otlpHttpExporter({ endpoint?, headers? }) is that default exporter — it POSTs
OTLP/JSON to ${endpoint}/v1/traces. toOtlpJson(spans) serializes collected
spans to the OTLP/JSON ResourceSpans shape a collector accepts, if you ship
them some other way.
A span carries method, url.full, server.address, status, and timings — never
request headers or bodies. url.full is the only attribute that can hold a
secret, so it is scrubbed before export: userinfo is stripped and the values of
secret-bearing query params (api_key, access_token, signature, …) become
REDACTED.
See Reference → Helpers for the helper signatures and Reference → Events for the event types each span is built from.
Export is fire-and-forget: a missing collector or network error drops the batch and never breaks a stitch call.
Defense in depth, not a guarantee: url.full is scrubbed before export
— userinfo stripped, secret-bearing query values masked — but that is a
best-effort denylist, so an unusually named param can still slip through.
Resolve a secret as a header-borne capability so it never enters the URL the
span exports in the first place (headers are never exported at all). See
Capability, not credential.