PostHog
Datafly Signal delivers events to PostHog server-to-server using the capture API (/i/v0/e/). Events are sent directly from your Signal deployment to PostHog, so delivery is unaffected by ad blockers, browser tracking prevention, or client-side script failures.
Why route PostHog through Datafly Signal
- Your numbers stop depending on what the browser allows. Client-side analytics loses every visit where the tag is blocked or the page unloads early. Signal delivers from the server, so PostHog receives the complete event stream.
- Client IP and user agent are carried in the payload. Both are taken from the original visitor request rather than your server, which is what PostHog needs to attribute the event to the right session.
- One consent decision governs every destination. PostHog is gated by the same consent state as the rest of your stack, so a withdrawal applies everywhere at once.
Prerequisites
Before configuring PostHog in Signal, you need a PostHog project and its Project API Key.
Create or open a PostHog project
- Sign in at PostHog (US Cloud) or eu.posthog.com (EU Cloud), or open your self-hosted instance.
- Create a project if you don’t already have one.
Find your Project API Key
- Go to Settings > Project.
- Copy the Project API Key (a write-only token that starts with
phc_).
The Project API Key is a public, write-only token. It can only send events — it cannot read data from your project — so it is safe to use as the capture credential.
Note your data region
PostHog Cloud runs in two independent regions. Your project lives in exactly one of them:
- US Cloud — ingestion host
us.i.posthog.com - EU Cloud — ingestion host
eu.i.posthog.com
For self-hosted PostHog, use your own instance host.
The region must match the project. A US token sent to the EU host (or vice versa) is silently rejected — events return a success-shaped response but never appear in your project.
Configure in Signal
| Field | Required | Description |
|---|---|---|
project_api_key | Yes | Your PostHog Project API Key (starts with phc_). Settings > Project > Project API Key. |
ingestion_host | Yes | Your data region: us.i.posthog.com, eu.i.posthog.com, or your self-hosted host. |
Management UI Setup
- Go to Integrations > Add Integration > PostHog.
- Enter your
project_api_key. - Select your Ingestion Host (data region).
- Select consent categories (typically
analytics). - Click Save.
API Endpoint
POST https://us.i.posthog.com/i/v0/e/ # US Cloud
POST https://eu.i.posthog.com/i/v0/e/ # EU CloudEach event is sent as a single JSON object. The Project API Key travels in the request body as api_key — there is no Authorization header.
{
"api_key": "phc_xxxxxxxxxxxxxxxxxxxx",
"event": "$pageview",
"distinct_id": "user-123",
"properties": {
"$current_url": "https://example.com/pricing"
},
"timestamp": "2026-06-06T12:00:00.000Z"
}Identity Signals
PostHog identifies users by a distinct_id that must be present on every event (an event without one is dropped with a 200).
| Signal | Field | Description |
|---|---|---|
distinct_id | distinct_id | The signed-in user ID (user_id) when known, else Signal’s anonymous_id. |
| Merge | $identify with properties.$anon_distinct_id | datafly.identify() is sent as PostHog’s $identify event: distinct_id is the user ID and $anon_distinct_id the anonymous ID, so PostHog merges pre-login activity into the person. |
| Groups | properties.$groups.company | The group() ID on every event; group() itself is sent as $groupidentify. |
| IP address | properties.$ip | Visitor IP from the original request, for GeoIP. |
| User agent | properties.$raw_user_agent | Visitor user agent. |
| Page | properties.$current_url, $pathname, $referrer | From the page context. |
Person properties
No personal data is sent. PostHog stores person properties in plain text and the capture API does not need them, so the presets do not set $set fields. Where you have a lawful basis, add $set mappings (for example $traits.email to properties.$set.email) on your installed integration.
Event Mapping
Events keep Signal’s canonical names (see the event specs), with each documented property as a PostHog event property; currency is upper-cased. PostHog’s reserved events are used where PostHog defines one:
| Signal event | PostHog event |
|---|---|
page | $pageview |
screen_view | $screen ($screen_name) |
identify | $identify |
group | $groupidentify |
| everything else | the Signal event name |
Presets: Default (page, screen, identify, group, sign-up, login, search, product, cart, checkout, purchase, refund, lead, subscription start and cancel), Retail (the ecommerce spec), B2B / SaaS (the SaaS spec) and Insurance (the insurance spec). Money events (purchase, policy_purchased, subscription_renewed, …) also carry revenue for PostHog revenue analytics. Only mapped properties are sent: an unmapped property is dropped, so add a mapping to forward a custom property.
Example: purchase
datafly.track("purchase", {
transaction_id: "ORD-001", value: 129.99, currency: "usd",
items: [{ item_id: "SKU-A", item_name: "Widget", price: 49.99, quantity: 2 }]
});{
"api_key": "phc_xxxxxxxxxxxxxxxxxxxx",
"event": "purchase",
"distinct_id": "user-123",
"timestamp": "2026-06-06T12:00:00.000Z",
"properties": {
"$ip": "203.0.113.50",
"$lib": "datafly-signal",
"$current_url": "https://example.com/checkout/complete",
"transaction_id": "ORD-001",
"value": 129.99,
"revenue": 129.99,
"currency": "USD",
"items": [{ "item_id": "SKU-A", "item_name": "Widget", "price": 49.99, "quantity": 2 }]
}
}Testing Your Integration
Trigger events
Browse your site or call datafly.track() / datafly.identify() to generate events.
Watch the PostHog Activity view
- In PostHog, open Activity (the live events feed).
- New events should appear within seconds, tagged with their
distinct_idand properties.
Verify identity merging
- Open People and search for the user ID.
- After an
identifycall, the person’s events include the activity recorded under the anonymous ID.
Check web analytics
- Open Web analytics.
- Confirm page views populate paths and referrers — these come from
$pageviewwith$current_urland$referrer.
Troubleshooting
| Problem | Solution |
|---|---|
| Events not appearing | Confirm the ingestion host matches the project’s region (US token to US host, EU to EU). A region mismatch is silently rejected. |
| Events accepted but person not identified | Ensure distinct_id is stable — events for the same user must share the same distinct_id. Check the user_id → anonymous_id fallback resolves. |
| GeoIP / location missing | Confirm $ip is being forwarded; PostHog resolves location from the IP property server-side. |
| Person properties empty | The presets send no person properties; add $set mappings on the installed integration if you need them. |
| Page views missing from web analytics | Confirm the page event maps to $pageview and carries $current_url. |
Notes
- PostHog’s capture endpoint answers an accepted event with HTTP
200and{"status":"Ok"}; an invalid token is a401. An event with no name or nodistinct_idis dropped with a200, which is whydistinct_idis required in the blueprint. - Self-hosted PostHog is supported: set the ingestion host to your own instance.