Python tracing installation
Contents
There are two ways to send spans from Python.
posthog | OpenTelemetry | |
|---|---|---|
| Packages | The SDK you already use for analytics | opentelemetry-sdk and an OTLP exporter |
| Instrumentation | Manual – you wrap the operations you care about | Manual, plus auto-instrumentation for Django, Flask, FastAPI, databases, and more |
| Person and session join | Automatic inside a PostHog context that identifies them | Set the attributes yourself |
Pick OpenTelemetry if you already run it, if you use asyncio with AsyncPosthog, or if you want spans from your web framework and database driver without writing them yourself. Pick posthog if PostHog is your only tracing backend and you'd rather instrument a handful of operations by hand than add an exporter pipeline.
Both routes send OTLP spans to the same endpoint, so you can start with one and switch later without losing your traces.
With posthog
Minimum version:
posthog7.58.0 or later.
- 1
Install posthog
RequiredTerminal - 2
Enable tracing
RequiredTracing is off until you set the
tracesoption. There's no OpenTelemetry dependency to add.PythonOption Description service_nameIdentifies the service in the Tracing UI. Maps to service.nameservice_versionRelease version. Maps to service.versionenvironmentDeployment environment, e.g. production. Maps todeployment.environmentresource_attributesAdditional OpenTelemetry resource attributes Use your project token (the same one you use for capturing events), not a personal API key. Tracing works with the synchronous
Posthogclient and the module-level API, notAsyncPosthog.See the Python SDK docs for batching, queue, and span-limit options, and
before_span_sendfor scrubbing attributes or dropping spans before they're exported. - 3
Create spans with posthog
Requiredstart_spanused in awithblock makes the span active for the block and ends it when the block exits. Spans started inside the block nest underneath it automatically.PythonIf an exception escapes the block, the span records it, its status is set to
error, and the exception propagates unchanged.Span names should be low-cardinality operation names –
GET /users/:id, notGET /users/123. Variable values belong in attributes.For work that can't wrap a block, call
start_spanwithoutwithand callend()yourself. See the Python SDK docs for the full span API and for continuing a trace across services with W3Ctraceparentheaders. - 4
Link spans to people and sessions
RecommendedSpans created inside a PostHog context that has a distinct ID or session ID carry
posthogDistinctIdandsessionIdattributes, which is what makes a trace reachable from a person or a Session Replay recording.PythonIf you use Django, the contexts middleware sets this up for every request, and reads the
X-POSTHOG-DISTINCT-IDandX-POSTHOG-SESSION-IDheaders thattracing_headerssends from the browser. - 5
Flush before the process exits
RecommendedQueued spans are exported on an interval, even with
sync_modeon, so a short-lived process can exit before they're sent. Bothflush()andshutdown()export spans that have already ended.PythonIn a serverless handler, call
flush()before returning. Callshutdown()when the process is genuinely exiting.
With OpenTelemetry
- 1
Install OpenTelemetry packages
RequiredFor the complete SDK reference, see the OpenTelemetry Python docs.
Terminalopentelemetry-exporter-otlp-proto-httpis the OTLP HTTP/protobuf trace exporter. The-proto-grpcvariant sends gRPC, so pick-proto-httpto match this guide. - 2
Get your project token
RequiredYou'll need your PostHog project token to authenticate trace requests. This is the same token you use for capturing events with the PostHog SDK.
Important: Use your project token which starts with
phc_. Do not use a personal API key (which starts withphx_).You can find your project token in Project settings.
- 3
Configure the SDK
RequiredSet up the OpenTelemetry SDK to export spans to PostHog over OTLP HTTP.
PythonThe
.http.segment in the import path is what selects the HTTP/protobuf exporter.Alternatively, configure the exporter with environment variables:
TerminalNote: Pass the full
/i/v1/tracespath to the traces endpoint. Don't use the baseOTEL_EXPORTER_OTLP_ENDPOINTvariable, which appends its own/v1/traces. - 4
Create spans
RequiredWrap the operations you want to measure in spans, and attach attributes for context.
PythonTo join these spans to a person or a Session Replay recording, set
posthogDistinctIdandsessionIdattributes yourself, from theX-POSTHOG-DISTINCT-IDandX-POSTHOG-SESSION-IDheaders thattracing_headerssends from the browser.
Next steps
CheckpointWhat you can do with your tracesAction Description Why you need distributed tracing What a trace shows you that nothing else does Explore traces Read a trace as a waterfall to see where time goes Filter spans Narrow down by service, status, duration, and attributes Propagate context Pass trace context across services so spans join the same trace