Skip to main content
If you already track signup, purchase, subscribe, churn, or any other product event in PostHog, you can pipe those events into Greenflash in real time. Your existing PostHog instrumentation becomes the outcome layer for your AI conversations — Greenflash uses the events to figure out which conversations correlate with revenue, retention, and churn.

How it works

PostHog has a built-in HTTP Webhook destination that POSTs a JSON-templated request for every event you forward. Greenflash gives you a per-product URL to paste into that destination. From there:
  1. A user action fires an event in PostHog ($identify, purchase, your own custom event, etc.).
  2. PostHog’s destination filters decide whether to forward it.
  3. PostHog POSTs the event to your Greenflash URL.
  4. Greenflash authenticates the URL token, maps the event to a Greenflash business event, infers whether it’s a positive / negative / neutral outcome, and attaches it to the product you connected.
  5. The next time Greenflash analyzes a conversation, it has the downstream events as context — so “did this conversation lead to anything?” becomes answerable.
No code in your app changes. PostHog stays the source of truth for events; Greenflash just consumes a copy of the ones you choose to forward.

Before you start

  • A Greenflash product you want to enrich with PostHog events. Create one under Settings → Products if you don’t have one yet.
  • A PostHog project with admin access so you can create a destination in the data pipeline.
  • (Optional) A list of the events you want to forward. Forwarding everything works but burns destination volume on noise like $pageview and $autocapture.

Setup

1. Create the connection in Greenflash

  1. Open Settings → Connect → Events in the Greenflash web app.
  2. Click Connect on the PostHog card.
  3. Pick the product the stream should feed and click Create source.
  4. Copy the destination URL. Greenflash shows it once. If you lose it, rotate the token from the connection row and update PostHog.
The URL is the secret. Anyone with the URL can write events into the connected product — treat it like an API key, store it in PostHog and a secrets manager only.

2. Add the destination in PostHog

  1. In PostHog, open Data pipeline → Destinations.
  2. Search for HTTP Webhook (described as “Sends a webhook templated by the incoming event data”) and click Create.
  3. Paste the Greenflash URL into the destination URL field. Leave the HTTP method as POST.
  4. (Optional but recommended) Under Filters, exclude $pageview, $pageleave, $autocapture, and $feature_flag_called, and allow only the business events you care about — typically signup, activation, purchase, upgrade, cancel, refund. PostHog forwards everything by default, so this is where you control volume.
  5. Save and enable the destination.
The connection row in Greenflash flips from Awaiting first event to Active the moment the first event lands.

3. Send a test event

Fire the event from PostHog or post directly to the URL to confirm the round trip:
curl -X POST "<YOUR_GREENFLASH_URL>" \
  -H "Content-Type: application/json" \
  -d '{
    "event": {
      "event": "purchase",
      "distinct_id": "user_test_123",
      "timestamp": "2026-05-18T12:00:00Z",
      "uuid": "00000000-0000-0000-0000-000000000001",
      "properties": {
        "$revenue": 49.0,
        "plan": "pro"
      }
    }
  }'
A successful request returns:
{ "received": 1, "accepted": 1, "dropped": 0 }
If accepted is 0 and dropped is 1, the event was filtered by your connection’s allowlist or denylist. If you get 401, the URL token is wrong (or has been rotated). See Troubleshooting.

How events are mapped

Greenflash applies these defaults to every PostHog event:
PostHog fieldGreenflash field
event.eventeventType
event.distinct_idexternalUserId
event.timestampeventAt
event.uuidinsertId (prefixed posthog:) — used for idempotency
event.properties.$revenuevalue (with valueType: currency)
event.properties (entire object)properties (preserved verbatim on the event row)

Identity hints (used for user & organization attribution)

Greenflash inspects a handful of $set fields to attach the event to the right user and organization. Sending these from PostHog means Greenflash can auto-create the user / org if it hasn’t seen them yet, instead of leaving the event unattached.
PostHog fieldGreenflash field
event.properties.$set.email (or top-level email)userHints.email
event.properties.$set.first_name + $set.last_name (or $set.name)userHints.name
event.properties.$groups.organization or $groups.company (or $set.organization_id)externalOrganizationId
event.properties.$set.organization_name (or $set.company)organizationHints.name
Greenflash never reads clerk_user_id — Clerk IDs are a Greenflash-internal identifier, not a trustworthy field to receive from an analytics provider.

Attribution: how events tie to users, orgs, and conversations

Users. Events match an existing Greenflash user in this order: by externalUserId (= PostHog distinct_id), then by email. If no match exists and the event carries an email, Greenflash upserts a new user automatically using the $set fields above — anonymous events (no email) keep userId = null instead of bloating the user table. Organizations. Same idea, scoped to externalOrganizationId. We never match orgs by name (collisions across customers make it unsafe), so the org upsert path only runs when $groups.organization (or equivalent) is present. Conversations. Attribution falls through three layers:
  1. Explicit. Add gf_conversation_id to the PostHog event’s properties to attach it to a specific Greenflash conversation (matched by externalConversationId). Always wins when set.
  2. Implicit recency fallback. If no gf_conversation_id is supplied and we resolved the user, the event attaches to the user’s most-recent conversation in this product within the last 15 minutes.
  3. Unattached. If neither holds, the event is stored against the product (and user, when known) but conversationId stays null.
Users and orgs auto-created from analytics carry properties.created_from = 'analytics' and properties.source = 'posthog' so they’re filterable downstream. When you later identify them via the Greenflash SDK using the same externalUserId, the existing row is reused (no duplicates).

Influence (positive / negative / neutral)

Greenflash classifies the kind of outcome each event represents so analyses can tell wins from losses:
  • Positive when $revenue > 0, or the event name matches signup, signed_up, upgrade, purchase, subscribe, convert, activate, complete, or order_completed.
  • Negative when $revenue < 0, or the event name matches churn, cancel, unsubscribe, refund, downgrade, delete, failed, or error.
  • Neutral otherwise.
Matching is case-insensitive and works across snake_case, kebab-case, PascalCase, and Title Case With Spaces.

Override the defaults

Need to ship a non-standard event name or pin a custom influence? Add any of these magic properties on the PostHog side and Greenflash will respect them — no Greenflash-side configuration required.
PropertyEffect
gf_event_typeOverride the Greenflash event name (the original PostHog name stays in properties)
gf_influenceForce positive, negative, or neutral
gf_quality_impact_scoreNumeric override from -1.0 to 1.0 — fine-grained weight
gf_valueOverride the event value (string or number)
gf_value_typeOne of currency, numeric, text, boolean
gf_conversation_idAttach this event to a specific Greenflash conversation (externalConversationId)
Example: forward a custom retention event but tell Greenflash to treat it as a positive outcome with a tighter weight.
posthog.capture('weekly_active_milestone', {
  weeks: 4,
  gf_influence: 'positive',
  gf_quality_impact_score: 0.6,
});

Filtering: what to forward

Filter on the PostHog side, not inside Greenflash. PostHog ships a rich filter builder with property matching, regex, and per-event triggers — anything we’d build into Greenflash would be a strict downgrade. We deliberately don’t expose a denylist UI: the only Greenflash-side knob is the magic-property overrides above, applied per event in the payload. A good rule of thumb: forward business events, drop telemetry. Out of the box PostHog sends everything including $pageview, $pageleave, $autocapture, and $feature_flag_called — most of that is noise for outcome analysis and costs you destination volume. Configure the HTTP Webhook destination’s Filters to allow only the events that signal real outcomes.
Forward signup, trial_started, activated, subscription_started, subscription_upgraded, subscription_cancelled. Greenflash will infer influence from the names — no magic properties needed. Use this to answer “which AI conversations led to a paid conversion vs. a cancel?”
Forward order_completed, refund_issued, cart_abandoned. Include $revenue on each so Greenflash can dollar-weight outcomes per conversation. Refunds should arrive with negative $revenue.
Forward feature-adoption milestones (workspace_created, integration_connected, first_value_reached). Tag them with gf_influence: 'positive' if the event name doesn’t match Greenflash’s defaults.
Don’t want to touch PostHog’s filter config for a short outage or experiment? Pause the connection from its row in Settings → Connect → Events. The Greenflash receiver returns 204 while paused so PostHog stops retrying. Re-enable to resume — no token rotation, no PostHog change.

Response codes & limits

CodeMeaning
200Event received and processed. Body includes received, accepted, dropped.
204Connection is paused or disconnected in Greenflash. Returned deliberately so PostHog doesn’t retry.
400Payload didn’t match the PostHog webhook schema (missing event, missing distinct_id, malformed JSON).
401URL token is invalid, the connection has been rotated, or the optional shared secret header is missing/wrong.
404Provider segment of the URL is wrong (e.g. you pointed PostHog at the /segment/ URL by mistake).
500Greenflash couldn’t look up the connection. Safe to retry.
PostHog’s HTTP Webhook destination POSTs one event per request, so there’s no batch size limit on this provider. Compare with Amplitude / Segment, which support up to 1,000 events per batch.

Security

The URL is path-authenticated: the token segment is generated per connection, stored only as a scrypt hash, and verified in constant time on every request. For defense in depth, you can configure a shared secret alongside the URL token. The secret is communicated to Greenflash on every request via a custom HTTP header — there’s no body field or query parameter.
  1. In PostHog, open your HTTP Webhook destination and go to Headers.
  2. Add a header with name x-greenflash-secret and value <your-secret> (any string you pick, 8+ characters).
  3. Provide the same secret to Greenflash on the connection so we can match it.
Once configured, Greenflash rejects any request whose x-greenflash-secret header is missing or doesn’t match with 401. Rotating the URL invalidates the previous token immediately. Events sent to the old URL return 401. Update the PostHog destination URL to resume delivery.

Troubleshooting

Most often this is a destination filter dropping everything. Check:
  • The destination is enabled in PostHog.
  • The destination’s filters aren’t excluding all your events.
  • The URL has no trailing slash and matches exactly what Greenflash showed you.
  • PostHog’s destination is firing — check the Activity tab on the destination in PostHog.
Either rename the event to match one of the Greenflash defaults, or add gf_influence and gf_quality_impact_score to the event properties. You can do this in your posthog.capture(...) call or with a PostHog destination transformation.
PostHog refund events need a negative $revenue value (e.g. $revenue: -49.0) for Greenflash to infer negative influence from the dollar amount. Alternatively set gf_influence: 'negative' directly.
Open the PostHog row under Settings → Connect → Events and click Rotate URL. The old token is invalidated immediately. Paste the new URL into the PostHog destination configuration.
Greenflash deduplicates on the posthog:<uuid> insert id. As long as PostHog sends a consistent uuid per event, retries from PostHog won’t create duplicates. If you’re posting to the URL yourself, include a stable uuid per event.

Next

How Greenflash uses events

What changes in your analyses once events start flowing.

Public Events API

Skip the webhook and post events directly if you want full control.