Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions contents/docs/distributed-tracing/installation/index.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
---
title: Install OpenTelemetry tracing
title: Install tracing
---

import TracingInstallationPlatforms from './_snippets/installation-platforms'

PostHog Tracing works with any OpenTelemetry-compatible client. You don't need any PostHog-specific packages – use standard OpenTelemetry libraries to export your spans.
PostHog Tracing works with any OpenTelemetry-compatible client – point its OTLP trace exporter at PostHog and you're done, with no PostHog-specific packages.

On Node.js, `posthog-node` can also create and export spans on its own, with no OpenTelemetry dependency. See the [Node.js guide](/docs/distributed-tracing/installation/nodejs) for both routes.

## Platforms

Expand Down
2 changes: 2 additions & 0 deletions contents/docs/distributed-tracing/installation/nextjs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ showStepsToc: true
import { Steps, Step } from 'components/Docs/Steps'
import TracingNextSteps from './_snippets/tracing-next-steps.mdx'

> **Already using `posthog-node` on the server?** Route handlers, server actions, and server components can create spans with its own span API instead of OpenTelemetry, with no extra packages – see the [Node.js guide](/docs/distributed-tracing/installation/nodejs). Either way, spans are server-side only: there is no browser span API.

<Steps>

<Step title="Install OpenTelemetry packages" badge="required">
Expand Down
128 changes: 122 additions & 6 deletions contents/docs/distributed-tracing/installation/nodejs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,121 @@ showStepsToc: true
---

import { Steps, Step } from 'components/Docs/Steps'
import InstallNodePackageManagers from '../../integrate/_snippets/install-node-package-managers.mdx'
import TracingNextSteps from './_snippets/tracing-next-steps.mdx'

There are two ways to send spans from Node.js.

| | `posthog-node` | OpenTelemetry |
| ------------------------------ | ----------------------------------------------------------- | -------------------------------------------------------------------- |
| **Packages** | The SDK you already use for analytics | Six `@opentelemetry/*` packages |
| **Instrumentation** | Manual – you wrap the operations you care about | Manual, plus auto-instrumentation for HTTP, Express, databases, and more |
| **Person and session join** | Automatic inside a PostHog request context | Set the attributes yourself |

Pick OpenTelemetry if you already run it, or if you want spans from your HTTP server and database driver without writing them yourself. Pick `posthog-node` 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-node`

> **Minimum version:** `posthog-node@5.52.0` or later.

<Steps>

<Step title="Install posthog-node" badge="required" titleSize="h3">

<InstallNodePackageManagers />

</Step>

<Step title="Enable tracing" badge="required" titleSize="h3">

Tracing is off until you set the `traces` option. There's no OpenTelemetry dependency to add.

```javascript
import { PostHog } from 'posthog-node'

export const posthog = new PostHog('<ph_project_token>', {
host: '<ph_client_api_host>',
traces: {
serviceName: 'checkout-api',
environment: 'production',
},
})
```

| Option | Description |
| -------------------- | -------------------------------------------------------------------- |
| `serviceName` | Identifies the service in the Tracing UI. Maps to `service.name` |
| `serviceVersion` | Release version. Maps to `service.version` |
| `environment` | Deployment environment, e.g. `production`. Maps to `deployment.environment` |
| `resourceAttributes` | Additional OpenTelemetry resource attributes |

Use your **project token** (the same one you use for capturing events), not a [personal API key](/docs/api#authentication).

See the [Node.js SDK docs](/docs/libraries/node#configuration) for batching, queue and span-limit options, and [`beforeSpanSend`](/docs/libraries/node#scrubbing-and-dropping-spans) for scrubbing attributes or dropping spans before they're exported.

</Step>

<Step title="Create spans" badge="required" titleSize="h3">

`withSpan` runs a callback with a span active for its duration and ends the span for you. Spans created inside the callback nest underneath it automatically.

```javascript
await posthog.withSpan('POST /checkout', { kind: 'server' }, async (span) => {
span.setAttribute('plan', user.plan)

const order = await posthog.withSpan('create-order', () => createOrder(cart))
await posthog.withSpan('charge-card', () => stripe.charge(order))

return order
})
```

If the callback throws or rejects, the span records the exception, its status is set to `error`, and your original error propagates unchanged.

Span names should be low-cardinality operation names – `GET /users/:id`, not `GET /users/123`. Variable values belong in attributes.

For work that can't wrap a callback, `startSpan` returns a span you end yourself. See the [Node.js SDK docs](/docs/libraries/node#distributed-tracing) for the full span API and for continuing a trace across services with W3C `traceparent` headers.

</Step>

<Step title="Link spans to people and sessions" badge="recommended" titleSize="h3">

Spans created inside a PostHog request context carry `posthogDistinctId` and `sessionId` attributes, which is what makes a trace reachable from a person or a Session Replay recording.

```javascript
posthog.withContext({ distinctId: user.id, sessionId }, async () => {
await posthog.withSpan('POST /checkout', () => processOrder())
})
```

If you use Express, the [PostHog middleware](/docs/libraries/node#add-request-context-to-express) sets this up for every request, and reads the `X-POSTHOG-DISTINCT-ID` and `X-POSTHOG-SESSION-ID` headers that [`tracing_headers`](/docs/libraries/js/config#tracing-headers) sends from the browser.

</Step>

<Step title="Flush before the process exits" badge="recommended" titleSize="h3">

Queued spans are exported on an interval, so a short-lived process can exit before they're sent. Both `flush()` and `shutdown()` export spans that have already ended.

```javascript
export const handler = async () => {
await posthog.withSpan('handler', () => doWork())
await posthog.flush()
}
```

In a serverless handler, call `flush()` rather than `shutdown()`: the container is reused across invocations, so `shutdown()` would throw away the connection pool and the flag cache. Call `shutdown()` when the process is genuinely exiting.

</Step>

</Steps>

## With OpenTelemetry

<Steps>

<Step title="Install OpenTelemetry packages" badge="required">
<Step title="Install OpenTelemetry packages" badge="required" titleSize="h3">

For the complete SDK reference, see the [OpenTelemetry JavaScript docs](https://opentelemetry.io/docs/languages/js/).

Expand All @@ -21,7 +131,7 @@ npm install @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-

</Step>

<Step title="Get your project token" badge="required">
<Step title="Get your project token" badge="required" titleSize="h3">

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.

Expand All @@ -31,7 +141,7 @@ You can find your project token in [Project settings](https://app.posthog.com/se

</Step>

<Step title="Configure the SDK" badge="required">
<Step title="Configure the SDK" badge="required" titleSize="h3">

Set up the OpenTelemetry SDK to export spans to PostHog over OTLP HTTP.

Expand Down Expand Up @@ -72,7 +182,7 @@ OTEL_SERVICE_NAME="my-service"

</Step>

<Step title="Create spans" badge="required">
<Step title="Create spans" badge="required" titleSize="h3">

Wrap the operations you want to measure in spans, and attach attributes for context.

Expand All @@ -98,11 +208,17 @@ function chargeCustomer(customerId) {
}
```

To join these spans to a person or a Session Replay recording, set `posthogDistinctId` and `sessionId` attributes yourself, from the `X-POSTHOG-DISTINCT-ID` and `X-POSTHOG-SESSION-ID` headers that [`tracing_headers`](/docs/libraries/js/config#tracing-headers) sends from the browser.

</Step>

<Step title="Test your setup" badge="recommended">
</Steps>

<Steps>

<Step checkpoint title="Test your setup" subtitle="Confirm spans are reaching PostHog">

Once everything is configured, confirm spans are reaching PostHog:
Whichever route you took:

1. Run your application and trigger the instrumented code
2. Open the PostHog Tracing interface
Expand Down
6 changes: 4 additions & 2 deletions contents/docs/distributed-tracing/start-here.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import { QuestLog, QuestLogItem } from "components/Docs/QuestLog";
<QuestLog firstSpeechBubble="Let's set up tracing!" lastSpeechBubble="Time to explore your traces!">

<QuestLogItem
title="Install an OpenTelemetry trace exporter"
title="Install a trace exporter"
subtitle="Required"
icon="IconCode"
>

PostHog Distributed Tracing works with any OpenTelemetry client. No PostHog-specific packages are required. Use the OTel SDKs you already have, point your trace exporter at PostHog's HTTP endpoint, and add your project token.
PostHog Distributed Tracing works with any OpenTelemetry client. Use the OTel SDKs you already have, point your trace exporter at PostHog's HTTP endpoint, and add your project token.

On Node.js you can skip OpenTelemetry entirely: `posthog-node` creates and exports spans itself, and spans made inside a request context carry the person and session they belong to. See the [Node.js guide](/docs/distributed-tracing/installation/nodejs).

Set these on your OpenTelemetry SDK:

Expand Down
Loading
Loading