PostHog can send a completed purchase, signup, or qualified lead to an ad platform without relying on a browser pixel alone. In PostHog, a destination turns a selected event into a server-to-server request as the event is processed. (+)
PostHog offers conversion templates for Meta, Google Ads, Microsoft Advertising (Microsoft Ads Conversions), LinkedIn, TikTok, Reddit, Pinterest, Snapchat and OpenAI Ads. All nine native templates are alpha; Pinterest also has an older Segment-compatible destination. (+) The guides below cover all nine.
A destination can work alongside the platform’s browser pixel or tag. Before both report the same conversion, set up the platform’s deduplication rules below: the event name, shared conversion ID and account or conversion action all matter. Bring a defined source event, matching identifiers, recorded advertising permission, and the conversion’s original time, value and currency.
In this guide
How to Build Consistent UTMs for Reliable Marketing Attribution
Give every campaign consistent UTM names and verify the results in PostHog. Capturing a parameter alone does not guarantee the channel classification you expect.
How to send PostHog conversion events to LinkedIn Ads
If the Insight Tag also reports the conversion, use separate browser and server rules with one shared event ID so LinkedIn counts it once.
How to send PostHog conversion events to Microsoft Ads
Microsoft can accept an event while dropping optional fields. Check response warnings and the goal’s action before relying on conversion totals.
How to send PostHog conversion events to OpenAI Ads
Validate without saving a conversion. When both the Pixel and server send one, check their amounts and identifiers: OpenAI keeps the first copy.
PostHog Google Ads Integration: Conversion Tracking
Use PostHog for Google Ads conversions that happen at least six hours after an ad click. Earlier uploads fail, and PostHog does not automatically retry them.
PostHog Meta Ads Integration: Conversion Tracking
Use PostHog alongside the Meta Pixel without counting the same conversion twice. Match event IDs, map available customer information, and test the result.
PostHog Pinterest Ads Integration: Conversion Tracking
Send PostHog purchases and leads to Pinterest, match catalog product IDs, and prevent duplicate Pixel events. Test the native destination before enabling it.
PostHog Reddit Ads Integration: Conversion Tracking
Send PostHog conversions to Reddit with a valid click ID, the right revenue format, and a shared Pixel event ID. Check delivery and attribution separately.
PostHog Snapchat Ads Integration: Conversion Tracking
PostHog misses Snap’s mixed-case click ID, and the default Event ID needs a source edit for Pixel deduplication. Fix both before sending live conversions.
PostHog TikTok Ads Integration: Conversion Tracking
Send leads and purchases from PostHog to TikTok with matching event IDs, customer details, and accurate order values. Check the response before enabling live traffic.
PostHog Transformations: Save Visitor IPs to Person Properties
Save a visitor’s IP from a browser event when privacy settings allow it, then map that value into later server-side conversions.
URL Parameters for Ads, by Platform: UTMs and Click IDs for PostHog
Keep UTMs consistent across ad platforms and capture click IDs separately so later conversions can be matched. Snapchat needs an extra PostHog mapping.
What a destination does and what it leaves to you
Every enabled mapping that matches an event can send a request. If two mappings match the same purchase, you may send it twice. Check the filters before enabling a destination. (+)
A destination reads person properties as they exist when PostHog processes the event. Identifying the person or adding an email afterward does not enrich that earlier destination run. Put matching data on the event and map it explicitly, or identify the person before the conversion. (+)
Retries cover network failures and HTTP 408, 429, 500, 502, 503 and 504. They default to three scheduled attempts, and a dropped connection can also get one immediate retry. (+ / + / +) A validation rejection such as HTTP 400, or an error inside an otherwise successful response, needs your intervention; it is not held for a later retry. Google’s six-hour click rule is an important example.
Inspect failures in the destination’s invocation logs and metrics. Prolonged slow execution or repeated code errors can lead to quarantine and eventual disabling. (+) A quota limit skips invocations rather than queuing them; raising a billing limit later does not recover data lost while that limit applied. (+ / +)
Your saved destination keeps its code and inputs. A newer catalogue template does not automatically replace them, although PostHog sometimes runs targeted migrations. (+) You still own click capture, identity timing, visitor context, consent, shared IDs and the checks inside the ad platform.
Before you start
Define the conversion. Decide whether it means a completed payment, a qualified lead or another business outcome, and which system confirms it. Write its trigger, owner and properties in your event tracking plan.
Make identity available in time. With the browser SDK’s default person_profiles: 'identified_only', a personless browser purchase has no person properties available to the destination, and a later identify() cannot repair that run. Identifying needs no login: a guest checkout can identify the buyer by customer ID or email. Backend SDKs process person profiles by default. (+ / +) Google skips events without a GCLID or email/phone identifiers; Pinterest skips without email, a mobile ad ID, or IP plus user agent; Snapchat skips without email, phone, or IP plus user agent. Check the event’s resolved inputs, including when a buyer never signs in. (+)
Preserve the ad click at landing. PostHog JavaScript captures supported URL click IDs and keeps first-touch $initial_<param> and latest <param> person properties when a profile is processed. A direct first visit can leave the initial click ID empty even after a later ad visit. (+) Follow the ad URL parameters guide to check the delivered landing URL and storage.
With mask_personal_data_properties enabled, supported URL click IDs become <masked>, which is non-empty but cannot identify an ad click. (+) Snapchat’s mixed-case ScCid needs separate capture; the SDK looks for lowercase sccid. (+) Current SDKs read Meta’s _fbc and _fbp cookies, but do not supply the other platforms’ _ttp, _scid or _epik cookie values. Masking URL parameters does not switch off Meta cookie reads; gate sharing on the recorded advertising permission below. (+) The SDK overwrites a cookie-only LinkedIn li_fat_id with null when the URL lacks the parameter; preserve the landing ID explicitly. OpenAI’s __obref needs separate capture. (+) Follow the OpenAI reference setup to preserve its browser reference.
Keep campaign names consistent. Use the UTM naming guide so you can compare your own campaign reporting with the platform’s results.
Supply the visitor’s context for backend conversions. A webhook or backend request can carry the sending server’s IP and lacks the visitor’s browser user agent and page URL. Meta and Snapchat require the conversion page’s URL for website events and default to the event’s $current_url, which billing events do not acquire automatically: save the URL with the order and map it. (+ / +) No native template here reads an IP saved on the person by default; Meta and Google do not map an IP at all. (+) Use the visitor IP and user-agent guide to capture and map the right context. Saving the IP alone does not change the outgoing request.
When Discard client IP data is enabled, event IP fields are removed before destinations read them. New projects in PostHog Cloud EU inherit that default; check the project’s setting before depending on IP-based matching. (+ / +)
Filter on advertising permission. A browser SDK opt-out stops that device’s event capture; it does not stop an independently sent billing webhook or backend event. (+) Have your consent tool record the permission to share data with the ad platform, carry it onto server events, and require it in each mapping’s property filter. An illustrative property is ads_consent: send only when it is explicitly true, including on backend events. This is a property your application supplies, not a PostHog default.
Exclude internal and test traffic. Configure your internal-user rules and enable Filter out internal and test users on the destination. Inline person-property filters work; a cohort must be dynamic and contain only person-property conditions. Static, behavioral or empty cohorts fail destination-filter compilation and stop matching events from being sent. (+ / +)
Which events to send, and how many destinations
Start with the outcomes your campaigns are meant to optimize: a paid order, qualified lead, booked appointment or activated subscription. Give each platform event one PostHog event or action that represents that outcome. If two captured events describe one order, choose the authoritative trigger before adding mappings.
In our subscription integrations, we separate trial starts, first payments, trial conversions and renewals before mapping them to ads. Paid events carry actual revenue, and we save browser context from page views for later billing events.
Remove default mappings you do not intend to send. Meta’s Page Viewed → PageView, TikTok’s Page Viewed → Pageview, Reddit’s Page Visit → PageVisit, Pinterest’s Page viewed → page_visit, Snapchat’s Page viewed → PAGE_VIEW and OpenAI’s Page viewed → page_viewed all match every $pageview. Google’s Conversion mapping starts with no event selection: set an explicit conversion filter before enabling it. Microsoft’s Conversion mapping also needs a source event and goal action. LinkedIn has no mapping presets: select its source event in the destination’s Filters. (+)
Check existing senders first. Shopify’s Meta channel sends server-side Purchase events at the Enhanced and Maximum data-sharing levels; Meta also offers a one-click Conversions API setup. (+ / +) Leave an already-sent conversion with that source unless you coordinate its IDs, or disable it there when moving ownership. The Meta prerequisites explain the duplicate-sender check.
Plan Google delivery separately. An upload tied to a click less than six hours old fails with TOO_RECENT_EVENT; PostHog’s realtime destination does not wait six hours or automatically replay the rejection. (+) A later qualified lead can fit this path. For an immediate web purchase, use the Google delivery guidance to choose the tag or a separately managed delayed-upload path while retaining the real conversion time.
For templates with mapping presets, use one destination with several mappings when the same account and credentials receive several conversion types. Give every mapping its own filter and fields, and split destinations when credentials, consent rules or ownership differ. LinkedIn's current template selects one conversion rule per destination, so create a destination for each rule. (+ / +)
Use filters and input expressions before editing Hog. Edit the source for Google consent or braid fields, Snapchat’s top-level event ID, or TikTok’s response-code check. Reddit’s value-unit fix belongs in its mapping. Add the LinkedIn request header to meet its API contract and use Microsoft’s email edit to prepare the address for hashing without blocking other usable identifiers. For OpenAI, add validation-only mode when you need to test without saving a conversion. Once you customize code, you own its payload contract, tests and API-version updates. (+)
How the nine platforms differ
Compare your saved destination with these October 2026 template defaults; older instances can differ. Each platform name opens its guide for setup and verification.
Setup and default mappings
All nine native templates carry the Experimental warning. PostHog does not offer official customer support for unexpected issues with them, so verify requests and platform responses before sending live conversions. (+)
| Platform | Connect with | Template endpoint | Starting mappings |
|---|---|---|---|
| Meta | Dataset (Pixel) ID + access token | Graph API v25.0 | Eight mappings, including PageView and Purchase. |
| Google Ads | Google OAuth + Customer ID + import conversion action | Google Ads API v24 | One Conversion mapping; select the source event. |
| TikTok | Pixel ID + access token | Events API v1.3/event/track/ | Eleven mappings; remove Pageview and review legacy event names. |
| Pixel ID + conversion access token; the PostHog field says Reddit Ads account ID | Conversions API v2.0 | Eight mappings, including PageVisit and Purchase. | |
| Ad account ID + conversion access token | API v5 | Native: eleven mappings, including page_visit and checkout. | |
| Snapchat | Snapchat OAuth + Pixel ID | Conversions API v3 | Eleven mappings, including PAGE_VIEW and PURCHASE. |
| LinkedIn OAuth + ad account + Conversions API rule | /rest/conversionEvents; LinkedIn-Version: 202607 | No mapping presets; one conversion rule per destination. Select the source event in Filters. | |
| Microsoft Advertising | UET Tag ID + Conversions API token; request account-manager access if the pilot option is unavailable | capi.uet.microsoft.com/v1/{tagId}/events | One Conversion mapping; select the source event and enter the goal's event action. |
| OpenAI Ads | Pixel ID + Conversions API key from Ads Manager | bzr.openai.com/v1/events?pid={pixelId} | Eight enabled presets, including page_viewed and order_created; remove unused mappings. |
Matching and deduplication
Meta, TikTok, Reddit, Pinterest, Snapchat, LinkedIn, Microsoft Advertising and OpenAI Ads default the ID to {event.uuid}, PostHog’s event UUID. (+) A separately installed browser pixel does not automatically know it. Use an order ID, lead ID or one generated conversion ID, and pass the identical value to both senders; reuse it for a retry, and give a new conversion a new ID. Google’s Order ID starts blank. For Google, check which conversion action counts the outcome: shared IDs prevent duplicates only within the same action, not across separate tag and import actions. (+)
| Platform | Deduplication rule | Click context | Hashing behavior |
|---|---|---|---|
| Meta | eventID ↔ event_id, same event name and dataset; 48 hours. | fbclid; use fbc for the API. | Default inputs hash email and first/last name. Code passes hashes through; normalize before hashing. |
| Google Ads | order_id is unique per import action. A separate tag action does not merge with it just because its transaction_id matches. | gclid; SDK also captures gbraid/wbraid, which the template does not send. | Code hashes raw email and phone. Do not supply already-hashed inputs; normalize first. |
| TikTok | event_id on both paths, same Pixel ID and event name; 48 hours. | ttclid; _ttp needs separate capture. | Inputs hash contact fields, external ID and postal code; code passes them through. |
conversionId ↔ conversion_id, same event type; Pixel copies pair only with CAPI WEBSITE events; two days. | rdt_cid → click_id. | Raw email is accepted and hashed by Reddit. Replace the default undocumented ip key with ip_address. | |
event_id on both paths, same event name; 48 hours. Offline events cannot be deduplicated. | epik; _epik needs separate capture. | Native code normalizes and hashes contact, address and external-ID fields into arrays; existing SHA-256 hashes pass through. | |
| Snapchat | client_dedup_id ↔ top-level event_id, same Pixel ID and event name; 48 hours. Purchase fallback: transaction_id ↔ order_id, up to 30 days. | ScCid needs explicit capture; stock sccid lookup misses its casing. | Default inputs hash contact, address and external-ID fields; click ID, IP and user agent stay raw. |
Insight Tag event_id ↔ API eventId, same ad account and separate browser/API rules; the browser copy takes reporting precedence. | li_fat_id → LINKEDIN_FIRST_PARTY_ADS_TRACKING_UUID. Cookie-only values are overwritten when the URL lacks the ID; preserve it explicitly. | The default input hashes email without normalization. Trim and lowercase before hashing; userInfo names remain plaintext at version 202607. | |
| Microsoft Advertising | UET event_id ↔ CAPI eventId, with the same UET tag and event name. | msclkid; CAPI expects the UUID without hyphens. | Code hashes raw email and phone. Prepare the email local part before hashing and omit malformed addresses without blocking other identifiers; retain + in an E.164 phone number. |
| OpenAI Ads | Pixel event_id ↔ API id, same Pixel ID and effective event name; first copy wins. Match custom_event_name for custom events. | oppref; automatic URL capture starts at posthog-js 1.435.6. Capture __obref separately. | Code trims/lowercases/hashes email and trims/hashes external ID while preserving its case. Do not pre-hash these inputs. |
Fix Snapchat before relying on ID deduplication. The stock template ignores its Event ID input and sends event_id inside custom_data; Snap’s cross-channel pair expects it at the event’s top level. Apply the Snapchat source fix and test both copies.
Value, time and testing
| Platform | Value and currency | Time and age | Testing |
|---|---|---|---|
| Meta | Numeric amount + ISO currency required for Purchase. Several defaults fall back to USD. | Unix seconds; website events up to seven days old. | Test Event Code shows events in Test Events, but Meta still uses them for targeting and measurement. |
| Google Ads | Numeric base-unit amount + ISO currency; mapping defaults are blank, so review the conversion action’s defaults too. | Time with UTC offset. Upload within 90 days of the click; 63 for enhanced conversions for leads, also within the action’s window. Minimum click age: six hours. | No validation-only input in this template. A real request uploads to the selected action. |
| TikTok | Numeric order total + supported ISO currency for ROAS/value optimization. Default currency fallback: USD. | Unix seconds. Send promptly; check the permitted age before backfilling. | Test Event Code; inspect Test Events and the response code. |
v2 value: integer minor units; value_decimal: base-unit number. Send one, with ISO currency. | RFC 3339 timestamp; within seven days. | Stock code fixes test_mode to false. Validation-only and Event Testing need a code change. | |
| String containing the pre-tax, pre-shipping total. ISO currency; omission uses the account’s creation currency. | Unix seconds; send within an hour, and check the permitted age before backfilling. | Native Test mode uses a sandbox; events do not feed reporting or optimization. | |
| Snapchat | Numeric value + supported currency required for PURCHASE; no currency fallback. | Stock template uses Unix seconds. Plan web delivery within seven days. | Test Event Mode uses /events/validate; validation is separate from live matching. |
| Decimal-string base-unit amount + ISO currency. Inputs start blank; review the rule's dynamic/fixed value policy. | Unix milliseconds; within 90 days. | No validation-only input in the template. A real test posts to the selected conversion rule. | |
| Microsoft Advertising | Numeric base-unit revenue + ISO currency; both inputs start blank. | Unix seconds; within seven days. | No validation-only input in the template. Inspect HTTP 200 warnings: invalid optional fields can be dropped. |
| OpenAI Ads | Integer standard minor units + ISO currency. With amount but no currency, the template omits both. | Unix milliseconds; within seven days, at most ten minutes in the future. | validate_only: true validates without saving; add it to the request body before a real test. |
Check the amount as well as the request. Reddit’s default puts a base-unit float into v2’s minor-unit value field: use the Reddit value correction. For an illustrative USD 49.95 merchandise subtotal before tax and shipping, Reddit takes value: 4995 or value_decimal: 49.95, and Pinterest the string "49.95". (+ / +) On Meta and TikTok, a USD fallback relabels an order with no currency as dollars; supply the order’s actual currency.
Check which Pinterest destination you have. The older Segment-compatible version defaults every mapping’s Opt Out to true, telling Pinterest the web visitor opted out of tracking. Follow the Pinterest migration guidance to map real permission or replace it with the native destination; do not turn opt-out off for everyone.
How to verify delivery, matching and attribution
Check three outcomes separately: delivered means the platform accepted the conversion; matched means it associated the conversion with a person; attributed means it credited an ad. PostHog’s destination logs and metrics help establish delivery, but they cannot prove the other two. (+)
Start with Make real HTTP requests switched off in PostHog’s test panel to inspect the evaluated inputs without sending them. It is on by default, so follow the platform’s test instructions before allowing real requests. (+ / +) Meta’s test code is also not a discard mechanism: those events still affect targeting and measurement. Use the platform-specific test behavior in the table.
- Choose one permitted conversion and inspect its resolved source event, destination account, original timestamp, shared ID, matching fields, amount and currency.
- Send a controlled request using the platform’s test mode where available. Check the response body as well as the HTTP status: Google reports partial failures inside the response, Pinterest reports each event’s status, and TikTok has its own response code. Snapchat and Pinterest can also skip events before sending, so a completed function is not proof of a delivered conversion.
- Inspect matching and deduplication on the platform. Meta’s verification uses Test Events, Event Match Quality and deduplication details; Google’s verification uses offline-upload diagnostics. Follow the equivalent checks for TikTok, Reddit, Pinterest, Snapchat, LinkedIn, Microsoft Advertising or OpenAI Ads. A field-coverage score alone does not prove that an individual conversion matched.
- After restoring production filters and removing test settings, follow a controlled real conversion into the platform’s ad reporting. Check a repeated ID and a genuinely new conversion, then check that denied advertising permission and internal traffic prevent a send.
Compare unique business IDs and values over the same reporting period, timezone and eligibility rules. Separate missing requests from unmatched people and unattributed conversions before changing the mapping. Use our conversion tracking audit to reconcile the platform’s totals with your orders or CRM.
If your destination is older
Inspect the saved code, inputs and mappings before rebuilding. Reset to template replaces the code and reconstructs template configuration, but keeps existing non-empty mappings and filters. It applies unsaved changes; review the inputs, restore deliberate custom behavior and test before saving. A source reset alone does not update the defaults inside retained mappings. (+)
- Meta with one global event name: per-event mappings merged into the template on 10 August 2026; rebuild with mappings if you need several Meta event types in one destination. (+)
- Meta without the click-age guard: inspect the saved
fbcexpression and code; the guard merged on 2 September 2026. The newer template drops malformed click IDs and IDs outside its age tolerance instead of repeatedly stamping an old click with a new time. (+) - Meta without an
fbpinput: add it; the template gained it in a change merged on 14 September 2026. (+) If its request still uses Graph APIv21.0, upgrade before 21 January 2027, when that version expires. (+) - posthog-js older than 1.426.0: upgrade for URL-derived
$fbc. Version 1.433.0 added reads of the Pixel’s_fbcand_fbpcookies as$fbcand$fbp. Confirm that the browser capture and destination mapping both use the available values. (+) - Google without email and phone inputs: those inputs merged on 29 July 2026; retained mappings may lack them. (+) Replace any remaining
/v21/or/v22/endpoint: those versions stopped accepting requests on 5 August and 7 October 2026, respectively. (+ / +) - Google access errors: since 15 June 2026, developer tokens with no offline-upload requests between 17 December 2025 and 15 June 2026 have been restricted from this endpoint. If you get
CUSTOMER_NOT_ALLOWLISTED_FOR_THIS_FEATURE, changing the API version does not grant access; follow the Google eligibility guidance and Data Manager migration route. (+) - Pinterest on the Segment-compatible template: check its Opt Out defaults. The native Pinterest Ads Conversions template merged on 29 September 2026; test a replacement before disabling the old sender and enabling the new one. (+)
- TikTok legacy event names:
CompletePaymentbecamePurchase, andSubmitFormbecameLead, on 1 May 2025. Those aliases remain supported indefinitely. ReplaceClickButtonandPlaceAnOrderbefore their 2027 retirement; their history cannot transfer to the replacement event. (+) - Reddit still on v2: plan a payload migration to v3 rather than changing only the URL. v2 is marked deprecated, but CAPI support continues without a published shutdown date. The Reddit guide covers the version choice. (+)
Frequently asked questions
Can PostHog send conversions to Meta’s Conversions API?
Yes. Use Meta Ads Conversions with the dataset’s Pixel ID and access token. Map the source conversion, and share its ID with the Meta Pixel if both send it. (+) The Meta setup guide covers the fields and tests.
How do I use PostHog events for paid-ads conversion tracking?
Define the source conversion, capture its matching data and advertising permission, configure a destination mapping, then verify delivery, matching and attribution. Use the platform comparison to open its setup guide; Google’s click-age restriction and Snapchat’s deduplication fix affect the delivery path you choose.
Which ad platforms can PostHog send conversions to?
Native conversion templates are available for Meta, Google Ads, Microsoft Advertising, LinkedIn, TikTok, Reddit, Pinterest, Snapchat and OpenAI Ads. All nine are experimental; this guide compares all nine with 99Ways setup guides. Pinterest also has a separate Segment-compatible template. (+)
Do I still need the platform’s pixel or tag?
Keep it if you need its browser events or identifiers; a server destination does not install that integration for you. Decide which path owns each conversion. If both send the same outcome, follow that platform’s event-name, ID and timing rules. Check Google’s conversion-action scope too; the table above gives the differences.
Why do my ad platform’s numbers differ from PostHog’s?
They count different sets of events: PostHog can record a conversion that your destination filters out, that the platform cannot match, or that earns no ad credit. Compare unique conversion IDs, values, dates, timezones and attribution settings before expecting equal totals; the reconciliation guide explains the checks.
Does a destination resend a conversion the platform rejected?
Not automatically for a payload rejection such as HTTP 400 or a per-event error inside HTTP 200. Automatic retries cover transient network failures, rate limits and selected server errors, with three scheduled attempts by default. Correct the cause and arrange a deliberate resend when appropriate, retaining the conversion’s original ID and time. (+ / +)

