Skip to main content
Zespan’s SDKs are built on top of OpenTelemetry, and both SDKs expose the underlying OTel API directly. Use this when you already run OTel infrastructure — Jaeger, Honeycomb, an OTel Collector, or any OTLP-compatible backend — and want Zespan-instrumented spans to also flow there, or when you need lower-level manual control over span creation than manual spans provides.
This page covers the OTel-native API — the same primitives (Span, SpanKind, SpanStatusCode) you’d use with the raw @opentelemetry/api / opentelemetry-api packages. If you just want to trace a custom operation and have it show up in the Zespan dashboard with evaluation scores, cost tracking, and status, use startSpan instead — it’s higher-level and integrates directly with Zespan’s own trace model.

When to use this instead of startSpan

  • You already export traces to an existing OTel backend and want Zespan’s spans to appear there too, dual-exported from the same instrumentation.
  • You need direct access to the underlying OTel Span object — for example, to set attributes with span.setAttribute() or interoperate with another library that expects a native OTel span.
  • You’re building an integration that needs a real TracerProvider registered globally (some auto-instrumentation libraries look for one).
If none of that applies, startSpan is almost always simpler — it doesn’t require a separate initOTel call and it feeds directly into Zespan’s cost, status, and evaluation-score model.

Relationship to enableOTel / otelEndpoint

The TypeScript and Python SDKs already have a simpler, declarative way to dual-export to an OTel backend: the enableOTel (enable_otel), otelEndpoint (otel_endpoint), and otelServiceName (otel_service_name) options passed to zespan.init() / zespan.init(). See Init options (TypeScript) and Init options (Python) for those. The functions on this page — initOTel/init_otel and friends — are the manual, lower-level equivalent. Use them when you need to configure the TracerProvider yourself (custom resource attributes, a non-default sampler, multiple span processors) or when you want to create and manage OTel spans directly rather than going through zespan.init()’s declarative config. The two mechanisms are independent — calling initOTel does not require enableOTel to be set, and vice versa.

initOTel(config) / init_otel(config)

Configures a global OpenTelemetry TracerProvider with a BatchSpanProcessor and an OTLP HTTP exporter, and registers it as the active provider. Call this once at application startup, before creating any spans with getTracer/get_tracer.
initOTel returns { tracer, provider } — the registered Tracer and the underlying NodeTracerProvider. init_otel returns None; call get_tracer() afterward to retrieve the tracer.

OTelConfig

string
default:"https://localhost:3001/v1/traces"
OTLP HTTP endpoint that spans are exported to. Point this at your own collector or backend.
Zespan’s OTLP endpoint accepts traces only. /v1/metrics and /v1/logs return 501. If your collector or SDK exports all three signals, point only the trace exporter at Zespan.Trace exports are capped at 1 MB and 512 spans per request — matching the OpenTelemetry SDK/Collector’s own default max_export_batch_size, so a default-configured exporter isn’t silently truncated — and count against your organization’s monthly event quota, exactly like the native /v1/ingest path. Anything beyond the cap comes back in partialSuccess.rejectedSpans; per the OTLP spec this is informational only, so raise your exporter’s batch size if you rely on it.
string
default:"zespan-sdk"
Service name attached as the service.name resource attribute on every exported span. TypeScript field: serviceName. Python field: service_name.
number
default:"1.0"
Fraction of traces to keep, decided once per trace from its trace id — the same enforcement the native SDKs use, not a per-event roll. TypeScript field: sampleRate. Python field: sample_rate.
Before this was enforced, an OTel-originated trace always sampled in at 100% regardless of this setting. If you’re upgrading from an older SDK version and already had sampleRate below 1.0 configured, your ingest volume will drop to match it — this is the fix taking effect, not new data loss.
string
When set, sent as the x-api-key header on every export request. TypeScript field: apiKey. Python field: api_key.
string
default:"production"
Attached as the deployment.environment resource attribute.
initOTel/init_otel registers a global TracerProvider. Call it once per process. Calling it again re-registers the provider and can produce duplicate exporters.

getTracer() / get_tracer()

Returns the Tracer instance created by initOTel/init_otel. Throws (TypeScript: Error; Python: RuntimeError) if called before initialization.

createSpan / create_span

Starts and returns a native OTel span from the tracer configured by initOTel/init_otel. You are responsible for ending the span yourself — prefer withSpan/with_span below unless you need to manage the span lifecycle manually (for example, ending it from a different function than the one that created it).
string
required
Span name.
SpanKind
default:"SpanKind.INTERNAL"
OpenTelemetry span kind. See SpanKind values below.
Record<string, string | number | boolean | string[]>
Attributes set on the span at creation time. TypeScript accepts attributes as an object property; Python accepts it as the attributes keyword argument (a dict).
In Python, kind and attributes are keyword-only arguments — create_span(name, *, kind=None, attributes=None).

withSpan / with_span

Wraps a function call in a span, setting SpanStatusCode.OK on success or SpanStatusCode.ERROR (with the exception recorded) on failure, and always ending the span. This is the recommended way to create spans with this API — it guarantees the span is closed exactly once regardless of outcome.
TypeScript: withSpan<T>(name, fn, options?)fn receives the span and returns a Promise<T>; withSpan returns that same Promise<T>. options accepts kind and attributes, same shape as createSpan. Python: with_span(name, *, kind=None, attributes=None) is an async context manager (@contextlib.asynccontextmanager) — use it with async with, not as a function that takes a callback. It yields the span.
On error, both implementations call record_exception/recordException and set SpanStatusCode.ERROR before re-raising — the exception always propagates. Neither implementation swallows errors.

SpanKind values

SpanKind is re-exported from @opentelemetry/api as-is — it’s not a Zespan-specific type. The common values:
TypeScript exports SpanKind directly from @zespan/sdkimport { SpanKind } from "@zespan/sdk". Python does not re-export SpanKind from the zespan package; import it from OpenTelemetry directly — from opentelemetry.trace import SpanKind.

SpanStatusCode values

Used with span.setStatus({ code }) (TypeScript) / span.set_status(code) (Python) to record the outcome of the work a span covers.
TypeScript exports SpanStatusCode directly from @zespan/sdk. Python does not — the underlying OTel API names this enum StatusCode, not SpanStatusCode. Import it yourself: from opentelemetry.trace import StatusCode.

BaggageSpanProcessor

BaggageSpanProcessor is currently TypeScript-only — there is no Python equivalent exported from the zespan package.
A SpanProcessor that copies every entry in the current OTel baggage onto each span as a baggage.<key> attribute when the span starts. Zespan’s injectAgentContext/extractAgentContext helpers use OTel baggage to carry agent delegation metadata (agent.delegation.reason, agent.task) across an HTTP call to another service. Registering BaggageSpanProcessor on your TracerProvider is what makes that propagated metadata show up as searchable span attributes on the receiving side, rather than only being available on the wire.
BaggageSpanProcessor implements the standard OTel SpanProcessor interface (onStart, onEnd, shutdown, forceFlush) — add it alongside any other span processors (such as the BatchSpanProcessor used internally by initOTel) on a TracerProvider you construct yourself. It only acts on onStart; onEnd, shutdown, and forceFlush are no-ops.
initOTel does not register a BaggageSpanProcessor automatically. If you want baggage entries copied onto span attributes, add it explicitly when you construct your own TracerProvider.