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

  1. Sign in at PostHog (US Cloud) or eu.posthog.com (EU Cloud), or open your self-hosted instance.
  2. Create a project if you don’t already have one.

Find your Project API Key

  1. Go to Settings > Project.
  2. 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

FieldRequiredDescription
project_api_keyYesYour PostHog Project API Key (starts with phc_). Settings > Project > Project API Key.
ingestion_hostYesYour data region: us.i.posthog.com, eu.i.posthog.com, or your self-hosted host.

Management UI Setup

  1. Go to Integrations > Add Integration > PostHog.
  2. Enter your project_api_key.
  3. Select your Ingestion Host (data region).
  4. Select consent categories (typically analytics).
  5. 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 Cloud

Each 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).

SignalFieldDescription
distinct_iddistinct_idThe signed-in user ID (user_id) when known, else Signal’s anonymous_id.
Merge$identify with properties.$anon_distinct_iddatafly.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.
Groupsproperties.$groups.companyThe group() ID on every event; group() itself is sent as $groupidentify.
IP addressproperties.$ipVisitor IP from the original request, for GeoIP.
User agentproperties.$raw_user_agentVisitor user agent.
Pageproperties.$current_url, $pathname, $referrerFrom 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 eventPostHog event
page$pageview
screen_view$screen ($screen_name)
identify$identify
group$groupidentify
everything elsethe 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

  1. In PostHog, open Activity (the live events feed).
  2. New events should appear within seconds, tagged with their distinct_id and properties.

Verify identity merging

  1. Open People and search for the user ID.
  2. After an identify call, the person’s events include the activity recorded under the anonymous ID.

Check web analytics

  1. Open Web analytics.
  2. Confirm page views populate paths and referrers — these come from $pageview with $current_url and $referrer.

Troubleshooting

ProblemSolution
Events not appearingConfirm 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 identifiedEnsure 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 missingConfirm $ip is being forwarded; PostHog resolves location from the IP property server-side.
Person properties emptyThe presets send no person properties; add $set mappings on the installed integration if you need them.
Page views missing from web analyticsConfirm the page event maps to $pageview and carries $current_url.

Notes

  • PostHog’s capture endpoint answers an accepted event with HTTP 200 and {"status":"Ok"}; an invalid token is a 401. An event with no name or no distinct_id is dropped with a 200, which is why distinct_id is required in the blueprint.
  • Self-hosted PostHog is supported: set the ingestion host to your own instance.