Send Events From PostHog
Send the conversions you already track in PostHog to Revnu, so your ads optimise on them without the Revnu Tag or the ad platforms' pixels.
If you already track sign-ups, bookings and purchases in PostHog, PostHog can send each one to Revnu as it happens. Revnu ties it to the ad click that brought the person and passes it on to Google, LinkedIn, Reddit and your other ad platforms, so your campaigns learn from real conversions.
Set it up in PostHog
Open Data pipelines, then Destinations, and add a new HTTP Webhook destination.
Set the webhook URL to
https://revnu.com/api/measurement/posthogand the method toPOST.Leave the JSON body as PostHog's default:
{"event": "{event}", "person": "{person}"}.Under Secret headers (not Headers), add
Authorizationwith the valueBearerfollowed by your event key. Secret headers are encrypted and kept out of PostHog's logs. The key starts withrsk_live_and is in Ads → Revnu Tag, under Install Details and Keys.Under the destination's filters, match only your conversion events, such as your sign-up, booked call and purchase events. Don't send page views.
Turn on Log responses, so Revnu's answer for each event, including any
not_matchable_reason, shows in the destination's logs.Enable the destination.
Revnu stores each event under its name in lowercase snake_case: Signed Up becomes signed_up, checkout completed becomes checkout_completed. Your win definition in Revnu has to count those names. The response's event_name shows the name Revnu stored.
What Revnu reads from each event
| From PostHog | Used for |
|---|---|
event.uuid |
The event id. PostHog's retries of the same event are recorded once. |
event.event |
The event name, converted to snake_case. |
event.timestamp |
When it happened. |
utm_* and click ids (gclid, li_fat_id, rdt_cid, fbclid, msclkid, ttclid, twclid, gbraid, wbraid) on the event, its $current_url, or its session's landing page ($session_entry_*) |
Which ad click and campaign brought the person. |
The person's email (or $set.email) and phone |
Hashed on arrival, then used to match the person on your ad platforms. |
event.distinct_id |
Hashed. Joins a later event, such as a payment captured on your server, to the same person's earlier sign-up. |
revenue or value, with currency |
The conversion's value, in whole currency units. Read on every event, not only the first purchase. |
reversal_of |
The uuid of an earlier event this one cancels. See Cancellations and refunds. |
attribution_captured_at |
When the click on this event was first seen, if you save attribution yourself. See If you save your own attribution. |
| Your own event properties | Kept for your win definition's rules. PostHog's $ properties, emails, names and IP addresses are dropped. |
Revnu never stores a raw email, phone, name, IP address or distinct id from PostHog.
Make every conversion matchable
An ad platform can only use a conversion that carries the click id from the ad, or the person's email or phone. To make sure yours do:
Identify people in PostHog with their email (
posthog.identify(userId, { email })) when they sign up.Capture sign-ups and bookings in the browser, or in the same session as the ad click, so the landing page's click id rides along.
Capture server-side events, such as Stripe payments, with the same
distinct_idyou identify the person with in the browser.
A conversion with no click id, email or phone is still recorded, and the response includes not_matchable_reason.
If you save your own attribution
Some sites save the UTMs and click ids from the landing page and put them on every later event, so a purchase weeks after the click still carries them. That works with Revnu if you also:
Save
revnu_campaign_idfrom the landing page URL along with your UTMs, as an event property of that name. Revnu adds it to every ad it runs, and it is how a conversion is tied to the campaign. Without it, Revnu falls back to the session's landing page or the person's earlier events.Send
attribution_captured_at, the time the click was first seen (ISO 8601, or Unix milliseconds as a number or a string of digits). Without it, Revnu treats the click as happening when the event did, and a click older than your win definition's click window would still get credit.
Cancellations and refunds
Send a cancellation or refund as its own event, with a reversal_of property set to the uuid of the event it cancels. If the original carried revenue and currency, repeat the same values; Revnu only takes back a whole conversion, never part of one.
When a reversal arrives:
Revnu stops counting the original in your results.
Google Ads gets a retraction, so the conversion is removed there too. Google can't retract a conversion matched only on
wbraid; Revnu flags those for review instead.LinkedIn, Reddit, X and Microsoft have no way to take a conversion back once it is sent, so it stays counted on those platforms.
A cancellation without reversal_of is recorded as its own event and leaves the original counted.
If cancellations are common and you run ads beyond Google, consider counting the later, firmer event (a held call rather than a booked one) as your win.
Where each conversion goes
Revnu sends a conversion to the ad platform whose Revnu campaign brought the person, within your win definition's click window (1 to 90 days). Conversions from campaigns you run yourself, outside Revnu, are not sent.
| Platform | How Revnu sends it | What it matches on |
|---|---|---|
| Google Ads | Offline click conversion import, into a conversion action Revnu creates | The click id (gclid, gbraid or wbraid). Email is not sent to Google |
| Conversions API, on a conversion rule Revnu creates | li_fat_id and the hashed email |
|
| Conversions API, on your ad account's pixel | rdt_cid and the hashed email |
|
| X | Conversions API, on a conversion event Revnu creates | twclid and the hashed email |
| Microsoft Advertising | Offline conversion import, into a goal Revnu creates | msclkid |
When a conversion carries both a click id and an email, Revnu sends both and the platform matches on whichever it can. Conversions that land days or weeks after the click are fine, as long as they are inside the click window.
Every outcome in your win definition is sent with its own value, so an upgrade event that carries the increase in revenue reports expansion revenue. Campaigns bid on the outcome they were launched for; later outcomes are reported alongside it.
Response
Same as the Event API, plus:
not_matchable_reasonappears when the event carried no ad click id and no email or phone, and wasn't joined to the person's earlier event, so no ad platform can match it.
| Code | Meaning |
|---|---|
| 200 | Recorded and credited to one of your Revnu ad campaigns, or a retry of an event already recorded |
| 202 | Recorded, not credited to a campaign |
| 400 | The body is not PostHog's webhook body. Restore the destination's default JSON body |
| 401 | Missing or invalid event key in the Authorization header |
| 413 | Body over 64 KB |
| 422 | A field failed validation; error says which |
| 429 | Rate limited. PostHog retries |
Frequently Asked Questions
Do I still need the Revnu Tag or the ad platforms' pixels?
No. PostHog sends the conversions, and Revnu sends them to your ad platforms through their conversion APIs. The Revnu Tag adds visit-level reporting on top, but ads can optimise without it.
Do I need to turn anything on in my ad accounts?
No. Connect the ad accounts to Revnu. Revnu creates the conversion actions, rules and events it sends to. Google's Enhanced Conversions and its customer data terms are not needed, because Revnu sends Google the click id, not the email.
Why does my conversion say not_matchable_reason?
PostHog sent it without an ad click id and without the person's email or phone. Identify people with their email in PostHog, and capture the event in the browser or with the same distinct_id as the person's browser events.
Will PostHog's test button create a real event?
Only if you turn off mocking in the test panel. A real test request is recorded like any other conversion.