> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# PostHog

<!-- -->

[Server](#)[ ](https://github.com/elbwalker/walkerOS/tree/main/packages/server/destinations/posthog)

<!-- -->

[Source code](https://github.com/elbwalker/walkerOS/tree/main/packages/server/destinations/posthog)[ ](https://www.npmjs.com/package/@walkeros/server-destination-posthog)

<!-- -->

[Package](https://www.npmjs.com/package/@walkeros/server-destination-posthog)

Server-side event delivery to PostHog for product analytics, identity resolution, group analytics, and feature flags via the official `posthog-node` SDK.

<!-- -->

Where this fits

PostHog is a **server destination** in the walkerOS flow:

Sends events server-side to PostHog's ingestion API, translating walkerOS events into \`capture\`, \`identify\`, and \`groupIdentify\` calls with full control over identity and group resolution.

## Installation[​](#installation "Direct link to Installation")

```
npm install @walkeros/server-destination-posthog
```

* Integrated
* Bundled

```
import { startFlow } from '@walkeros/collector';
import { destinationPostHog } from '@walkeros/server-destination-posthog';

await startFlow({
  destinations: {
    posthog: {
      code: destinationPostHog,
      config: {
        settings: {
          apiKey: 'phc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
          host: 'https://eu.i.posthog.com',
        },
      },
    },
  },
});
```

Add to your `flow.json` destinations:

```
"destinations": {
  "posthog": {
    "package": "@walkeros/server-destination-posthog",
    "import": "destinationPostHog",
    "config": {
      "settings": {
        "apiKey": "phc_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "host": "https://eu.i.posthog.com"
      }
    }
  }
}
```

[See bundled mode setup](https://www.walkeros.io/docs/getting-started/modes/bundled.md) | [CLI reference](https://www.walkeros.io/docs/apps/cli.md)

## Configuration[​](#configuration "Direct link to Configuration")

This <!-- -->destination<!-- --> uses the standard <!-- -->destination<!-- --> config wrapper (consent, data, env, id, ...). For the shared fields see [destination<!-- --> configuration](https://www.walkeros.io/docs/destinations.md#configuration). Package-specific fields live under `config.settings` and are listed below.

## Settings[​](#settings "Direct link to Settings")

| Property                      | Type            | Description                                                                                                                               | More |
| ----------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| `apiKey*`                     | `string`        | PostHog project API key (starts with "phc\_"). Find it in PostHog project settings.                                                       |      |
| `host`                        | `string`        | PostHog API host. Defaults to https\://us.i.posthog.com. Use https\://eu.i.posthog.com for EU or your self-hosted URL.                    |      |
| `flushAt`                     | `number`        | Number of events queued before auto-flush. Default: 20.                                                                                   |      |
| `flushInterval`               | `number`        | Milliseconds between periodic flushes. Default: 10000.                                                                                    |      |
| `personalApiKey`              | `string`        | Personal API key (phx\_...) for local feature flag evaluation.                                                                            |      |
| `featureFlagsPollingInterval` | `number`        | Milliseconds between feature flag definition polls. Default: 30000.                                                                       |      |
| `disableGeoip`                | `boolean`       | Disable GeoIP lookups globally. Useful for GDPR compliance.                                                                               |      |
| `debug`                       | `boolean`       | Enable PostHog SDK debug logging. Default: false.                                                                                         |      |
| `identify`                    | `any`           | walkerOS mapping value resolving to an identity object. Keys: distinctId, $set, $set\_once. Resolved on every push (server is stateless). |      |
| `group`                       | `any`           | walkerOS mapping value resolving to a group object. Keys: type, key, properties. Resolved on every push.                                  |      |
| `include`                     | `Array<string>` | Event sections to flatten into capture() properties (e.g. \["data", "globals"]).                                                          |      |

\* Required fields

## Mapping[​](#mapping "Direct link to Mapping")

Per-event rules under `config.mapping`. For the standard rule fields (consent, condition, data, batch, name, policy) see [mapping](https://www.walkeros.io/docs/mapping.md).

| Property   | Type  | Description                                                                                                                               | More |
| ---------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| `identify` | `any` | Per-event identity mapping. Resolves to { distinctId, $set?, $set\_once? }. Fires client.identify() when $set/$set\_once present.         |      |
| `group`    | `any` | Group assignment. Resolves to { type, key, properties? }. Fires client.groupIdentify() when properties present, adds groups to capture(). |      |

## Examples

### Capture with group

A destination-level group mapping attaches the resolved group context to every PostHog capture call.

Event

```
{
  "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",
    "company_id": "company_123"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "9b0675bc9bdbc590",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000104,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
client.capture({
  "distinctId": "us3r",
  "event": "page view",
  "properties": {},
  "groups": {
    "company": "company_123"
  }
})
```

### Capture with include

Destination-level include flattens data and globals sections into prefixed PostHog event properties.

Event

```
{
  "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": "d396bcfc7aef1792",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000101,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
client.capture({
  "distinctId": "us3r",
  "event": "order complete",
  "properties": {
    "data_id": "0rd3r1d",
    "data_currency": "EUR",
    "data_shipping": 5.22,
    "data_taxes": 73.76,
    "data_total": 555,
    "globals_pagegroup": "shop"
  }
})
```

### Consent granted

A walker consent command with analytics granted calls client.enable on the PostHog client.

Event

```
{
  "analytics": true
}
```

Out

```
client.enable()
```

### Consent revoked

A walker consent command with analytics denied calls client.disable on the PostHog client.

Event

```
{
  "analytics": false
}
```

Out

```
client.enable();

client.disable()
```

### Default capture

A walker event becomes a PostHog capture call with the user id as distinctId and no extra properties.

Event

```
{
  "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": "4ba86966bbf65160",
  "trigger": "load",
  "entity": "product",
  "action": "view",
  "timestamp": 1700000100,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
client.capture({
  "distinctId": "us3r",
  "event": "product view",
  "properties": {}
})
```

### Group identify

A company update fires PostHog groupIdentify with group type, key, and associated group properties.

Event

```
{
  "name": "company update",
  "data": {
    "company_id": "company_123",
    "company_name": "Acme",
    "plan": "enterprise"
  },
  "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": "ac506bac9f8cf08f",
  "trigger": "test",
  "entity": "company",
  "action": "update",
  "timestamp": 1700000103,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "silent": true,
  "settings": {
    "group": {
      "map": {
        "type": {
          "value": "company"
        },
        "key": "data.company_id",
        "properties": {
          "map": {
            "name": "data.company_name",
            "plan": "data.plan"
          }
        }
      }
    }
  }
}
```

Out

```
client.groupIdentify({
  "groupType": "company",
  "groupKey": "company_123",
  "properties": {
    "name": "Acme",
    "plan": "enterprise"
  }
})
```

### Identify with $set

A user login fires PostHog identify with $set and $set\_once person properties and skips the capture.

Event

```
{
  "name": "user login",
  "data": {
    "user_id": "new-user-123",
    "email": "user@acme.com",
    "plan": "premium"
  },
  "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": "46ff750f53670b31",
  "trigger": "test",
  "entity": "user",
  "action": "login",
  "timestamp": 1700000102,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "silent": true,
  "settings": {
    "identify": {
      "map": {
        "distinctId": "data.user_id",
        "$set": {
          "map": {
            "email": "data.email",
            "plan": "data.plan"
          }
        },
        "$set_once": {
          "map": {
            "first_login": "timestamp"
          }
        }
      }
    }
  }
}
```

Out

```
client.identify({
  "distinctId": "new-user-123",
  "properties": {
    "$set": {
      "email": "user@acme.com",
      "plan": "premium"
    },
    "$set_once": {
      "first_login": 1700000102
    }
  }
})
```
