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:- A user action fires an event in PostHog (
$identify,purchase, your own custom event, etc.). - PostHog’s destination filters decide whether to forward it.
- PostHog POSTs the event to your Greenflash URL.
- 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.
- The next time Greenflash analyzes a conversation, it has the downstream events as context — so “did this conversation lead to anything?” becomes answerable.
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
$pageviewand$autocapture.
Setup
1. Create the connection in Greenflash
- Open Settings → Connect → Events in the Greenflash web app.
- Click Connect on the PostHog card.
- Pick the product the stream should feed and click Create source.
- Copy the destination URL. Greenflash shows it once. If you lose it, rotate the token from the connection row and update PostHog.
2. Add the destination in PostHog
- In PostHog, open Data pipeline → Destinations.
- Search for HTTP Webhook (described as “Sends a webhook templated by the incoming event data”) and click Create.
- Paste the Greenflash URL into the destination URL field. Leave the HTTP method as
POST. - (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. - Save and enable the destination.
3. Send a test event
Fire the event from PostHog or post directly to the URL to confirm the round trip: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 field | Greenflash field |
|---|---|
event.event | eventType |
event.distinct_id | externalUserId |
event.timestamp | eventAt |
event.uuid | insertId (prefixed posthog:) — used for idempotency |
event.properties.$revenue | value (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 field | Greenflash 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: byexternalUserId (= 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:
- Explicit. Add
gf_conversation_idto the PostHog event’s properties to attach it to a specific Greenflash conversation (matched byexternalConversationId). Always wins when set. - Implicit recency fallback. If no
gf_conversation_idis supplied and we resolved the user, the event attaches to the user’s most-recent conversation in this product within the last 15 minutes. - Unattached. If neither holds, the event is stored against the product (and user, when known) but
conversationIdstaysnull.
Users and orgs auto-created from analytics carryproperties.created_from = 'analytics'andproperties.source = 'posthog'so they’re filterable downstream. When you later identify them via the Greenflash SDK using the sameexternalUserId, 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 matchessignup,signed_up,upgrade,purchase,subscribe,convert,activate,complete, ororder_completed. - Negative when
$revenue < 0, or the event name matcheschurn,cancel,unsubscribe,refund,downgrade,delete,failed, orerror. - Neutral otherwise.
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.| Property | Effect |
|---|---|
gf_event_type | Override the Greenflash event name (the original PostHog name stays in properties) |
gf_influence | Force positive, negative, or neutral |
gf_quality_impact_score | Numeric override from -1.0 to 1.0 — fine-grained weight |
gf_value | Override the event value (string or number) |
gf_value_type | One of currency, numeric, text, boolean |
gf_conversation_id | Attach this event to a specific Greenflash conversation (externalConversationId) |
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.
SaaS conversion funnel
SaaS conversion funnel
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?”E-commerce
E-commerce
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.Product-led growth
Product-led growth
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.Hard-mute a stream temporarily
Hard-mute a stream temporarily
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
| Code | Meaning |
|---|---|
200 | Event received and processed. Body includes received, accepted, dropped. |
204 | Connection is paused or disconnected in Greenflash. Returned deliberately so PostHog doesn’t retry. |
400 | Payload didn’t match the PostHog webhook schema (missing event, missing distinct_id, malformed JSON). |
401 | URL token is invalid, the connection has been rotated, or the optional shared secret header is missing/wrong. |
404 | Provider segment of the URL is wrong (e.g. you pointed PostHog at the /segment/ URL by mistake). |
500 | Greenflash couldn’t look up the connection. Safe to retry. |
Security
The URL is path-authenticated: the token segment is generated per connection, stored only as ascrypt 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.
- In PostHog, open your HTTP Webhook destination and go to Headers.
- Add a header with name
x-greenflash-secretand value<your-secret>(any string you pick, 8+ characters). - Provide the same secret to Greenflash on the connection so we can match it.
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
Connection still says ''Awaiting first event''
Connection still says ''Awaiting first event''
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.
Events arrive but influence is wrong
Events arrive but influence is wrong
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.Refunds aren't showing up as negative
Refunds aren't showing up as negative
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.Lost the URL
Lost the URL
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.
Duplicate events
Duplicate events
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.

