Traces

Tracing SDK, integration frameworks, and manual ingestion.
  1. Sign up — Create an account at platform.respan.ai
  2. Create an API key — Generate one on the API keys page
  3. Add credits or a provider key — Add credits on the Credits page or connect your own provider key on the Integrations page

Add the Docs MCP to your AI coding tool to get help building with Respan. No API key needed.

1{
2 "mcpServers": {
3 "respan-docs": {
4 "url": "https://docs.respan.ai/mcp"
5 }
6 }
7}

The Respan tracing SDK provides decorators and wrappers to instrument your code. This page covers the detailed features.


Decorators & span types

Use decorators (Python) or wrapper methods (JS/TS) to create spans. Each decorator creates a different span type in the trace tree.

DecoratorSpan typeUse for
@workflow / withWorkflowWorkflowTop-level parent span
@task / withTaskTaskIndividual steps within a workflow
@agent / withAgentAgentAgent-level operations
@tool / withToolToolTool/function calls
1from openai import OpenAI
2from respan_tracing.decorators import workflow, task
3from respan_tracing.main import RespanTelemetry
4
5k_tl = RespanTelemetry()
6client = OpenAI()
7
8@task(name="joke_creation")
9def create_joke():
10 completion = client.chat.completions.create(
11 model="gpt-3.5-turbo",
12 messages=[{"role": "user", "content": "Tell me a joke about opentelemetry"}],
13 temperature=0.5,
14 max_tokens=100,
15 )
16 return completion.choices[0].message.content
17
18@task(name="pirate_joke_translation")
19def translate_joke_to_pirate(joke: str):
20 completion = client.chat.completions.create(
21 model="gpt-3.5-turbo",
22 messages=[{"role": "user", "content": "translate to pirate language:\n\n" + joke}],
23 )
24 return completion.choices[0].message.content
25
26@workflow(name="joke_workflow")
27def joke_workflow():
28 joke = create_joke()
29 pirate_joke = translate_joke_to_pirate(joke)
30 return pirate_joke
31
32result = joke_workflow()
33print(result)

For the full SDK API reference, see the Python SDK or TypeScript SDK.


Class-based workflows

Apply @workflow to a class with method_name to designate the entry point. Use @task on individual methods.

1from openai import OpenAI
2from respan_tracing import RespanTelemetry
3from respan_tracing.decorators import workflow, task
4
5k_tl = RespanTelemetry()
6client = OpenAI()
7
8@workflow(name="joke_agent", method_name="run")
9class JokeAgent:
10 @task(name="joke_creation")
11 def create_joke(self):
12 completion = client.chat.completions.create(
13 model="gpt-3.5-turbo",
14 messages=[{"role": "user", "content": "Tell me a joke"}],
15 )
16 return completion.choices[0].message.content
17
18 def run(self):
19 return self.create_joke()
20
21agent = JokeAgent()
22result = agent.run()

Override span input & output

Control what appears as a span’s input/output in the trace UI using OpenTelemetry attributes:

Python
1import json
2from opentelemetry.semconv_ai import SpanAttributes
3from respan_tracing.main import RespanTelemetry
4from respan_tracing.decorators import workflow
5
6k_tl = RespanTelemetry()
7client = k_tl.get_client()
8
9@workflow(name="update_attributes_test")
10def update_attributes_test(input: str):
11 force_set_attributes = {
12 SpanAttributes.TRACELOOP_ENTITY_INPUT: json.dumps({
13 "args": [],
14 "kwargs": {"text": "custom input"}
15 }),
16 }
17
18 client.update_current_span(
19 attributes=force_set_attributes,
20 name="update_attributes_test",
21 respan_params={"metadata": {"test": "test"}},
22 )
23
24 return "Some desired output"
25
26if __name__ == "__main__":
27 update_attributes_test("Some input")

Use update_current_span(attributes=...) for overriding displayed input/output. Values must be JSON-serializable strings via json.dumps(...).


Integration frameworks

Respan supports 90+ integrations with popular AI frameworks. See the Integrations overview for the full list, or jump to:


Manual ingestion

Use manual ingestion when you have existing log data, custom telemetry pipelines, or OpenTelemetry setups that need to send traces to Respan without using a framework SDK.


OTLP endpoint

If you have an existing OpenTelemetry setup, send traces directly to Respan’s OTLP-compatible endpoint. This works with any OpenTelemetry SDK or collector.

POST https://api.respan.ai/api/v2/traces
Authorization: Bearer {RESPAN_API_KEY}
Content-Type: application/json (or application/x-protobuf)

Environment variable configuration

.env
$OTEL_EXPORTER_OTLP_ENDPOINT="https://api.respan.ai/api"
$OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer YOUR_RESPAN_API_KEY"
$OTEL_EXPORTER_OTLP_PROTOCOL="http/json"

SDK configuration

1from opentelemetry import trace
2from opentelemetry.sdk.trace import TracerProvider
3from opentelemetry.sdk.trace.export import BatchSpanProcessor
4from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
5
6exporter = OTLPSpanExporter(
7 endpoint="https://api.respan.ai/api/v2/traces",
8 headers={"Authorization": "Bearer YOUR_RESPAN_API_KEY"},
9)
10
11provider = TracerProvider()
12provider.add_span_processor(BatchSpanProcessor(exporter))
13trace.set_tracer_provider(provider)
14
15tracer = trace.get_tracer("my-service")
16with tracer.start_as_current_span("my-operation") as span:
17 span.set_attribute("gen_ai.request.model", "gpt-4")
18 # Your code here

Respan automatically parses OTel spans, extracts Gen AI semantic conventions and Respan-specific attributes, and maps them to the Respan data model. For the full OTLP schema and recognized attributes, see the OTLP ingest API reference.


Ingest API

Example project: Ingest traces example

Construct traces by posting spans as JSON. Every span is a JSON object. Spans with the same trace_unique_id are grouped into a single trace. Parent-child relationships are defined via span_parent_id.

Endpoint

POST {RESPAN_BASE_URL}/v1/traces/ingest
Authorization: Bearer {RESPAN_API_KEY}

Span fields

FieldTypeRequiredDescription
trace_unique_idstringYesGroups spans into a single trace
span_unique_idstringYesUnique ID for the span
span_parent_idstringParent span ID; omit or null for root spans
span_namestringName of the span (e.g. "openai.chat")
start_timestringSpan start time (RFC3339 UTC)
timestampstringSpan end time (RFC3339 UTC)
modelstringModel used
inputstring / objectSpan input data
outputstring / objectSpan output data
metadataobjectCustom key-value pairs

For the full list, see Span fields reference.

Example

$curl -X POST "$RESPAN_BASE_URL/v1/traces/ingest" \
> -H "Authorization: Bearer $RESPAN_API_KEY" \
> -H "Content-Type: application/json" \
> -d '[
> {
> "trace_unique_id": "a-trace-id",
> "span_unique_id": "root-span-id",
> "span_name": "workflow.start",
> "span_parent_id": null,
> "timestamp": "2025-09-08T07:46:14.007279Z",
> "start_time": "2025-09-08T07:46:14.007279Z"
> },
> {
> "trace_unique_id": "a-trace-id",
> "span_unique_id": "child-span-id",
> "span_name": "openai.chat",
> "span_parent_id": "root-span-id",
> "timestamp": "2025-09-08T07:46:19.041835Z",
> "start_time": "2025-09-08T07:46:18.037942Z"
> }
> ]'