Subchapter 93.9
references/php.mdMarkdown7 KBView on GitHub
AI agents: this is one page from PostHog’s docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt (opens in a new tab)
Cloud region: This page uses US Cloud hosts. For an EU Cloud project, use
https://eu.i.posthog.cominstead ofhttps://us.i.posthog.com(ingestion host), and usehttps://eu.posthog.cominstead ofhttps://app.posthog.com(app host for links).
1
Required
For the complete SDK reference, see the OpenTelemetry PHP docs (opens in a new tab).
composer require open-telemetry/api open-telemetry/sdk open-telemetry/exporter-otlp
composer require guzzlehttp/guzzle php-http/guzzle7-adapterThe OTLP HTTP transport needs a PSR-18 HTTP client and PSR-17 factories, which php-http/discovery finds at runtime. Guzzle (above) or symfony/http-client with nyholm/psr7 both work. For production, install the native protobuf extension (pecl install protobuf) – the pure-PHP fallback is slower.
2
Required
You’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 (opens in a new tab).
3
Required
Set up the OpenTelemetry SDK to export spans to PostHog over OTLP HTTP.
<?php
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
4
Required
Wrap the operations you want to measure in spans, and attach attributes for context.
$tracer = $tracerProvider->getTracer('my-service');
$span = $tracer->spanBuilder('process-order')->startSpan();
$scope =
5
Recommended
After your existing PostHog client is initialized, add the optional processor to your existing OpenTelemetry provider builder alongside its exporter:
use PostHog\OpenTelemetry\ContextSpanProcessor;
use PostHog\PostHog;
$tracerProvider = TracerProvider::builder()
->addSpanProcessor(new ContextSpanProcessor(
6
Recommended
Once everything is configured, confirm spans are reaching PostHog:
Checkpoint
What you can do with your traces
| Action | Description |
|---|---|
| Why you need distributed tracing (opens in a new tab) | 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 |
Alternatively, configure the SDK with environment variables and let it autoconfigure:
OTEL_PHP_AUTOLOAD_ENABLED=true
OTEL_SERVICE_NAME=my-service
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://us.i.posthog.com/i/v1/traces"
OTEL_EXPORTER_OTLP_TRACES_HEADERS="Authorization=Bearer <ph_project_token>"Note: Pass the full
/i/v1/tracespath to the traces endpoint. Don’t use the baseOTEL_EXPORTER_OTLP_ENDPOINTvariable, which appends its own/v1/traces.
Use this configuration in place of the builder above. Keep your existing provider, exporter, and sampler. Register the processor before requests start. OpenTelemetry SDK 1.0.0 or later is supported and remains an optional application dependency.
The processor reads this client’s PostHog context when each span starts. The Laravel request middleware (opens in a new tab) sets that context with PostHog::withContext(). With the processor registered, entering a context also enriches the active request span in normal PHP execution. Configure tracing_headers (opens in a new tab) for your backend hostname in the browser SDK.
Existing sessionId and posthogDistinctId span attributes take precedence. Missing IDs stay absent. The scope closes after success or failure, while spans that already started keep their attributes.
Fiber limit: Incoming spans that started before withContext() inside a Fiber are skipped. OpenTelemetry has no safe public check for initialized Fiber storage. Child spans can receive IDs from Fiber-local PostHog context when the application’s OpenTelemetry Fiber context is initialized. New Fibers and queue jobs need explicit context transfer.