PostHog
PostHog is an open-source product analytics platform
with session replay, feature flags, A/B testing, surveys, and heatmaps. This
destination forwards walkerOS events to PostHog via the official
posthog-js SDK, translating
events into posthog.capture(...) calls, resolving identity and group
assignments, and handling consent opt-in/opt-out. All built-in PostHog
features (session replay, feature flags, surveys, heatmaps, exception capture)
are available through SDK init passthrough.
PostHog is a web destination in the walkerOS flow:
Installation
npm install @walkeros/web-destination-posthog- Integrated
- Bundled
import { startFlow } from '@walkeros/collector';
import { destinationPostHog } from '@walkeros/web-destination-posthog';
await startFlow({
destinations: {
posthog: {
code: destinationPostHog,
config: {
settings: {
apiKey: 'phc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
api_host: 'https://eu.i.posthog.com',
},
},
},
},
});Add to your flow.json destinations:
"destinations": {
"posthog": {
"package": "@walkeros/web-destination-posthog",
"config": {
"settings": {
"apiKey": "phc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"api_host": "https://eu.i.posthog.com"
}
}
}
}Configuration
This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see destination configuration. Package-specific fields live under config.settings and are listed below.
Settings
| Property | Type | Description | More |
|---|---|---|---|
apiKey | string | Your PostHog project API key (starts with "phc_"). Find it in your PostHog project settings under "Project API Key" (like phc_a1b2c3d4e5f6789012345678abcdef12). | |
api_host | string | PostHog API host. Defaults to https://us.i.posthog.com. Use https://eu.i.posthog.com for the EU region. | |
ui_host | string | URL of the PostHog UI host, used by toolbar and replay player. Default: null. | |
persistence | Where to persist user identity. Default: "localStorage+cookie". | ||
person_profiles | When to create person profiles. "identified_only" (default) creates profiles only after identify() is called. | ||
autocapture | boolean | Enable PostHog's autocapture of clicks, form submits, and pageviews. Default: false (walkerOS sources handle capture). | |
capture_pageview | boolean | string | Whether PostHog should auto-capture pageview events. Default: false (walkerOS sources handle this). | |
capture_pageleave | boolean | string | Whether PostHog should auto-capture pageleave events. Default: false. | |
capture_heatmaps | boolean | Enable heatmap data capture. Default: true (PostHog default). | |
capture_exceptions | boolean | Enable automatic exception capture. Default: false. | |
disable_surveys | boolean | Disable PostHog surveys. Default: false. | |
disable_session_recording | boolean | Disable session recording. Default: false. | |
advanced_disable_flags | boolean | Disable feature flag loading. Default: false. | |
cookieless_mode | 'always' | 'on_reject' | "always" never uses cookies/localStorage. "on_reject" falls back to cookieless when consent is rejected. | |
debug | boolean | Enable PostHog SDK debug logging. Default: false. | |
session_recording | any | Session Replay options (SessionRecordingOptions). Masking, blocking, sampling. See PostHog docs for full list. | |
bootstrap | any | SSR bootstrap data. { distinctID?, featureFlags? } — pre-populates identity and flag values to avoid first-render flicker. | |
identify | any | walkerOS mapping value resolving to an identity object. Keys: distinctId, $set, $set_once. Resolved on first push and re-fired when distinctId changes. | |
group | any | walkerOS mapping value resolving to a group object. Keys: type, key, properties. Resolved on first push and re-fired when type/key changes. |
Mapping
Per-event rules under config.mapping. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
| Property | Type | Description | More |
|---|---|---|---|
identify | any | Per-event identity mapping. Resolves to an object with any of: distinctId, $set, $set_once. Omitting distinctId routes to setPersonProperties() (no identity change). | |
group | any | Group assignment. Resolves to { type, key, properties? } → posthog.group(type, key, properties). | |
reset | any | Logout trigger. Resolves to a truthy value → posthog.reset() (clears distinctId and regenerates an anonymous one). Typically used with silent: true on a user logout rule. |
Examples
Consent granted
A walker consent command with analytics granted calls posthog.opt_in_capturing to resume capture.
{
"analytics": true
}posthog.opt_in_capturing()Consent revoked
A walker consent command with analytics denied calls posthog.opt_out_capturing to stop capture and replay.
{
"analytics": false
}posthog.opt_in_capturing();
posthog.opt_out_capturing()Default capture
A walker event becomes a PostHog capture call with the event name and empty properties.
{
"name": "product view",
"data": {
"id": "ers",
"name": "Everyday Ruck Snack",
"color": "black",
"size": "l",
"price": 420
},
"context": {
"shopping": [
"detail",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [],
"consent": {
"functional": true
},
"id": "e9d7acad8cf24607",
"trigger": "load",
"entity": "product",
"action": "view",
"timestamp": 1700000100,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}posthog.capture("product view", {})Destination identify
Destination-level identify calls posthog.identify with the user id before firing the default capture.
{
"name": "page view",
"data": {
"domain": "www.example.com",
"title": "walkerOS documentation",
"referrer": "https://www.walkeros.io/",
"search": "?foo=bar",
"hash": "#hash",
"id": "/docs/"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"pagegroup": "docs"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "81dc65dc20319358",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000104,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}posthog.identify("us3r");
posthog.capture("page view", {})Include data
Destination-level include flattens the event data section into prefixed PostHog capture properties.
{
"name": "product view",
"data": {
"id": "ers",
"name": "Everyday Ruck Snack",
"color": "black",
"size": "l",
"price": 420
},
"context": {
"shopping": [
"detail",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [],
"consent": {
"functional": true
},
"id": "f40ce3c80355eccd",
"trigger": "load",
"entity": "product",
"action": "view",
"timestamp": 1700000102,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}posthog.capture("product view", {
"data_id": "ers",
"data_name": "Everyday Ruck Snack",
"data_color": "black",
"data_size": "l",
"data_price": 420
})Group assignment
A company update assigns the user to a PostHog group and sets group properties via posthog.group.
{
"name": "company update",
"data": {
"company_id": "company_123",
"company_name": "Acme",
"plan": "enterprise",
"size": 50
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "730347c424f98845",
"trigger": "test",
"entity": "company",
"action": "update",
"timestamp": 1700000108,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"silent": true,
"settings": {
"group": {
"map": {
"type": {
"value": "company"
},
"key": "data.company_id",
"properties": {
"map": {
"name": "data.company_name",
"plan": "data.plan",
"employee_count": "data.size"
}
}
}
}
}
}posthog.group("company", "company_123", {
"name": "Acme",
"plan": "enterprise",
"employee_count": 50
})Order complete
An order complete captures order data and globals as prefixed properties for revenue analysis in PostHog.
{
"name": "order complete",
"data": {
"id": "0rd3r1d",
"currency": "EUR",
"shipping": 5.22,
"taxes": 73.76,
"total": 555
},
"context": {
"shopping": [
"complete",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "product",
"data": {
"id": "ers",
"name": "Everyday Ruck Snack",
"color": "black",
"size": "l",
"price": 420
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "product",
"data": {
"id": "cc",
"name": "Cool Cap",
"size": "one size",
"price": 42
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "gift",
"data": {
"name": "Surprise"
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
}
],
"consent": {
"functional": true
},
"id": "531f548d11ca5cd3",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000109,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"include": [
"data",
"globals"
]
}posthog.capture("order complete", {
"data_id": "0rd3r1d",
"data_currency": "EUR",
"data_shipping": 5.22,
"data_taxes": 73.76,
"data_total": 555,
"globals_pagegroup": "shop"
})Set person properties
A profile update calls setPersonProperties to enrich the PostHog profile without changing identity.
{
"name": "profile update",
"data": {
"name": "Jane Doe",
"avatar_url": "https://example.com/avatar.png"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "746809e675a0c1f8",
"trigger": "test",
"entity": "profile",
"action": "update",
"timestamp": 1700000106,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"settings": {
"identify": {
"map": {
"$set": {
"map": {
"name": "data.name",
"avatar": "data.avatar_url"
}
}
}
}
}
}posthog.setPersonProperties({
"name": "Jane Doe",
"avatar": "https://example.com/avatar.png"
}, null);
posthog.capture("profile update", {})Rule include overrides
A per-rule include replaces the destination-level include so this event forwards only globals.
{
"name": "order complete",
"data": {
"id": "0rd3r1d",
"currency": "EUR",
"shipping": 5.22,
"taxes": 73.76,
"total": 555
},
"context": {
"shopping": [
"complete",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "product",
"data": {
"id": "ers",
"name": "Everyday Ruck Snack",
"color": "black",
"size": "l",
"price": 420
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "product",
"data": {
"id": "cc",
"name": "Cool Cap",
"size": "one size",
"price": 42
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
},
{
"entity": "gift",
"data": {
"name": "Surprise"
},
"context": {
"shopping": [
"complete",
0
]
},
"nested": []
}
],
"consent": {
"functional": true
},
"id": "ba761cc4ff0df985",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000103,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"include": [
"globals"
]
}posthog.capture("order complete", {
"globals_pagegroup": "shop"
})User login identify
A user login fires PostHog identify with $set and $set_once person properties, skipping the capture.
{
"name": "user login",
"data": {
"user_id": "new-user-123",
"email": "user@acme.com",
"plan": "premium",
"company": "Acme",
"source": "organic"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "855ffdbae6cf66aa",
"trigger": "test",
"entity": "user",
"action": "login",
"timestamp": 1700000105,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"silent": true,
"settings": {
"identify": {
"map": {
"distinctId": "data.user_id",
"$set": {
"map": {
"email": "data.email",
"plan": "data.plan",
"company": "data.company"
}
},
"$set_once": {
"map": {
"first_login": "timestamp",
"signup_source": "data.source"
}
}
}
}
}
}posthog.identify("new-user-123", {
"email": "user@acme.com",
"plan": "premium",
"company": "Acme"
}, {
"first_login": 1700000105,
"signup_source": "organic"
})User logout reset
A user logout calls posthog.reset to clear the distinct id and generate a new anonymous one.
{
"name": "user logout",
"data": {
"string": "foo",
"number": 1,
"boolean": true,
"array": [
0,
"text",
false
]
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "860df16f3607fb9d",
"trigger": "test",
"entity": "user",
"action": "logout",
"timestamp": 1700000107,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"silent": true,
"settings": {
"reset": true
}
}posthog.reset()Built-in features
All these PostHog features work via standard posthog-js init options, with no
destination wiring required:
- Session replay:
settings.session_recording: { maskAllInputs: true, ... } - Feature flags:
settings.bootstrap: { featureFlags: { ... } }for SSR - Surveys: automatic;
settings.disable_surveys: trueto opt out - Heatmaps:
settings.capture_heatmaps: true - Exception capture:
settings.capture_exceptions: true - Cookieless mode:
settings.cookieless_mode: 'always' | 'on_reject' - Person profiles:
settings.person_profiles: 'identified_only'(PostHog default, privacy-friendly) or'always'
walkerOS sets three defaults that differ from PostHog's built-ins:
autocapture: false, capture_pageview: false, capture_pageleave: false,
because walkerOS sources handle event capture. Override them explicitly if you
want PostHog's autocapture on.