Reddit’s Conversions API accepts events from a server, including conversions you already track in PostHog. Reddit can use them to match conversions to people and attribute them to ads. If you also run the Reddit Pixel, share a conversion ID between the browser and server events to prevent duplicates. (+)
As of October 2026, PostHog’s Reddit destination posts to Reddit’s v2.0 endpoint. (+) The setup below corrects its IP, value and testing defaults before you enable it.
To compare platforms, see our overview of PostHog’s ad destinations. To send events without PostHog, follow Reddit’s direct integration guide.
What you need before you start
Before creating the destination, make sure you have:
- A PostHog project already capturing the conversions you want Reddit to measure.
- The Pixel ID for the Reddit business receiving those conversions and a Conversion Access Token; Step 3 shows where to find them.
- The visitor’s identifiers and permission to share them for advertising.
- A decision on whether the Reddit Pixel also sends these conversions, and an ID both paths can share if it does.
Send only the conversion events you use for measurement or campaign optimization, such as purchases, leads, signups or add-to-cart events.
Step 1: Check the source conversions
The Reddit destination can only send the data you already have in PostHog.
In Activity, open several recent examples of each conversion event and check:
- For purchases: the order total, its currency, an order ID, product IDs and quantities.
- For leads and signups: the completed action, a unique lead or signup ID, and the user identifiers you have collected.
- For browser and backend events: whether the IP address and user agent belong to the visitor.
A destination reads person properties as they exist when PostHog processes the event. Properties added after PostHog processes the conversion, for example by a later identify() or $set call, are not available to that destination run. Include matching data on the conversion event itself, or identify the person before capturing it. (+)
If an event fires before the action is complete, fix its trigger first; our event tracking plan guide explains how to define the action and its properties.
Step 2: Open the Reddit Conversions API destination
In PostHog, open Destinations and click New destination. Search for Reddit Conversions API and click + Create. (+ / +)

PostHog marks this template Experimental and offers no official support for unexpected issues, so allow for template changes and verify delivery yourself. (+)
The configuration banner warns of a 10-events-per-second limit; Reddit’s CAPI-specific limits are 1,000 requests and 10,000 events per second for live traffic, with 10 events per second for test traffic. (+ / +) The template sends one event per request, so its live traffic also reaches the request limit at 1,000 events per second. (+)
CAPI v2 remains supported despite the general v2 deprecation notice, with no published CAPI v2 end date. (+) CAPI v3 has been available since October 2025. (+) If PostHog moves the template to v3, check every mapping against Reddit’s v2 to v3 migration guide.
The template sends no action_source, so v2 treats its events as WEBSITE. (+) The mappings below are for website conversions. For conversions that happen in an app, offline or elsewhere, use a separate destination: click Edit source code, add the channel inside let eventData := {, for example 'action_source': 'APP',, and map the match keys that channel provides. (+)
Step 3: Add the Pixel ID and access token
Enter the Pixel ID in PostHog’s field labelled Reddit Ads account ID. Reddit’s v2 endpoint takes the receiving Pixel’s ID in its path. Use that rather than a member or account ID: an incorrect ID can return a 404, and a member ID a 500 authorization error. (+ / +)
- In Reddit Ads, open Events Manager.
- Select Configure data source → Conversions API → Set up manually. If neither CAPI nor the Pixel is configured, select Conversions API Only.
- Select Copy to Clipboard to copy the Pixel ID, then paste it into PostHog.
For the token, go to Events Manager → Conversions API → Generate Access Token. Name it, select Generate and copy it before closing the pop-up: it cannot be retrieved afterwards. Conversion access tokens never expire, and you can generate up to 25. (+)
Only a business admin can generate the token. (+) Paste it into PostHog’s Conversion Access Token field.

Treat the access token like a secret. Do not paste it into public docs, screenshots, tickets, or client-facing notes.
Step 4: Choose events and remove unused defaults
A new destination starts with eight mappings, including $pageview → PageVisit. Delete the Page Visit mapping first unless you deliberately want to send page visits, then remove any other mappings you do not need. (+)
| Default PostHog event | Reddit Event Type |
|---|---|
$pageview | PageVisit |
Products Searched | Search |
Product Added | AddToCart |
Product Added to Wishlist | AddToWishlist |
Order Completed | Purchase |
Product Viewed | ViewContent |
Lead Generated | Lead |
Signed Up | SignUp |

Map your own event names to the closest Reddit type: for example, select your completed lead event and set Event Type to Lead. If a standard event fits, use it.
For a custom conversion, type its name, such as DemoBooked, into Event Type. When the name is not a standard type, the template sends tracking_type: Custom with that name in custom_event_name. Custom names are case-sensitive and may contain up to 64 characters, including spaces; only the 20 most recent custom events are visible on the dashboard. (+)
Step 5: Configure event filters
In each mapping, use Match events and actions to select the source conversion. Add property filters when the event name alone is not enough: for example, select form_submitted and require form_type to equal demo_request. Several PostHog events can share a mapping when they need the same Reddit type and metadata. (+)
Turn on Filter out internal and test users using your project’s internal-user filters. Prefer person-property rules here; behavioral cohorts cannot be evaluated by realtime destinations and cause errors. (+)
The destination sends personal data to Reddit. When the browser SDK is opted out, it captures no browser events for the destination to forward. (+) A billing webhook or backend capture is sent by another system, so the browser’s choice does not stop it. Record advertising permission with the conversion and require it in a mapping filter; for example, an event property named advertising_consent must be true. That name is illustrative: use the property your consent integration records, and exclude absent or denied permission.
Step 6: Map user parameters
Use every reliable match key you have, but do not invent values. A missing email is better than a fake or incorrectly transformed email.
In User parameters, delete the default ip entry, which hashes the address, and add ip_address with the visitor’s IP unhashed. The default does not populate Reddit’s IP field. (+)
| Reddit user key | What to enter or capture |
|---|---|
ip_address | For a browser conversion: {event.properties.$ip}. Use the saved visitor IP for backend conversions, as explained below. |
email | Keep the raw default {person.properties.email} when that property contains the visitor’s email. If the conversion event carries the email, use {event.properties.email ?? person.properties.email}. |
user_agent | The default is {person.properties.$raw_user_agent}. It must describe the visitor’s browser. |
external_id | Your product’s own stable user ID, stored as a string; an illustrative mapping is {person.properties.user_id ?? event.properties.user_id}. Send it with another attribution parameter or click_id, and use the same raw or hashed representation on both Pixel and API paths. |
phone_number | An E.164 number with a country code (illustrative: +15554441234), or its SHA-256 hash after formatting. Include the country code and remove extensions before hashing. |
uuid | Capture the Pixel’s _rdt_uuid cookie and pass its full value or UUID portion. This identifies the visitor; it is separate from a conversion ID. |
screen_dimensions | An object containing integer width and height, each greater than 0 and less than 32768. |
These are Reddit’s v2 user fields; ip, first name and last name are not among them. View conversions cannot be attributed without ip_address, user_agent and screen_dimensions. (+)
For device matching, IP is the minimum key Reddit asks you to pass. (+) On backend and billing events, event.properties.$ip can be the sending server’s address: PostHog fills it from the capture request when no IP is supplied. (+)
In our configuration, we read the saved visitor IP from the person first. Follow our guide to saving the visitor’s IP before using this backend mapping; the property must already contain a visitor IP, not a server address:
{person.properties.$ip}For RevenueCat, inspect subscriber_attributes.$ip on an actual event before using it as a fallback. RevenueCat includes customer attributes in its PostHog events, and its reserved $ip attribute is the device IP; this path depends on that attribute having been collected and forwarded. For purchases made in an app, set the channel as shown in Step 2. (+ / +)
{person.properties.$ip ?? event.properties.subscriber_attributes.$ip}If $ip is missing, check Settings → Project → IP data capture configuration → Discard client IP data. With that setting enabled, raw IPs are removed from stored events; retaining them is a project privacy decision. (+)
Reddit accepts raw email and normalizes and hashes it automatically, so the template’s raw email default is suitable. Raw phone numbers are supported too. (+)
If you pre-hash email, lowercase the address, remove dots from the local part, remove the + suffix before @, then SHA-256 hash it as 64 lowercase hex characters. For example, [email protected] must become [email protected] before hashing. Lowercasing alone produces a different hash. (+)
The default keeps screen_dimensions even when both dimensions are null. Replace its value with this expression to omit the object when valid dimensions are unavailable, including on server events:
{toInt(person.properties.$screen_width ?? 0) > 0 and toInt(person.properties.$screen_width ?? 0) < 32768 and toInt(person.properties.$screen_height ?? 0) > 0 and toInt(person.properties.$screen_height ?? 0) < 32768 ? {'width': toInt(person.properties.$screen_width), 'height': toInt(person.properties.$screen_height)} : null}If a server-only destination has no visitor screen data, remove the screen_dimensions entry. Do not substitute the server’s screen size or user agent.
Step 7: Map the Reddit click ID (rdt_cid)
Reddit appends rdt_cid to the landing URL after an ad click. Preserve it through redirects and check that the outgoing CAPI click_id equals the URL value. (+)
PostHog’s JavaScript SDK captures rdt_cid from the URL, rather than reading an _rdt_cid cookie. It masks the value as <masked> when mask_personal_data_properties is enabled. (+) See our ad URL parameter guide for capture and storage.
The Reddit Click ID (rdt_cid) input defaults to the latest person value, then the first-touch value: (+)
{person.properties.rdt_cid ?? person.properties.$initial_rdt_cid}
The person fields are rdt_cid and $initial_rdt_cid, but an anonymous event may carry the click ID without updating a person profile. (+) If you need the event value too, use this expression. It reads the event first and omits the chosen value if it is <masked>; a masked string is not a usable click ID:
{(event.properties.rdt_cid ?? person.properties.rdt_cid ?? person.properties.$initial_rdt_cid) = '<masked>' ? null : (event.properties.rdt_cid ?? person.properties.rdt_cid ?? person.properties.$initial_rdt_cid)}Do not assume rdt_cid is present. Test Reddit ad clicks and inspect the resulting PostHog person and event properties.
With Campaign Manager 360 click trackers, add &rdt_cid=%prdt_cid=!; to the landing page URL suffix so Reddit’s click ID reaches the page. (+)
Step 8: Map event-specific parameters
In Event parameters, use the fields appropriate to each conversion:
| Field | v2 value and purpose | Supported events |
|---|---|---|
value_decimal or value | Send one. value_decimal is the amount in the currency’s base unit; value is an integer in its smallest unit. Illustrative USD example: 10.99 versus 1099. | AddToCart, AddToWishlist, Lead, Purchase, SignUp, Custom; only when a monetary value applies. |
currency | Use the event’s ISO 4217 currency, such as USD or EUR. Reddit assumes the account currency when it is missing. | The same events as value, with a monetary amount. |
products | Each product needs id and category in the v2 request. Use the catalog’s variant ID (SKU or GTIN), rather than the parent ID; without variants, use the item’s assigned ID. name, quantity and item_price are optional. Product quantities and unit prices do not replace the event’s item_count and total value. | Product metadata can accompany all conversion types; include it for product ads and dynamic product ads. |
item_count | An integer for the total number of items in the event. | AddToCart, AddToWishlist, Purchase, Custom. |
conversion_id | A unique ID shared with the Pixel for the same conversion. | All conversion types, only when using both the Reddit Pixel and Conversions API. |
Value
Rename the template’s value key to value_decimal and keep the expression below if your source amounts are in base units. The template puts this float into value by default, alongside defaults for currency, products and conversion ID. (+)
{toFloat(event.properties.value ?? event.properties.revenue ?? event.properties.price)}Use net revenue, gross revenue, or another value definition consistently. Do not mix definitions across events.
For a purchase, use the order total; the price fallback is appropriate only when it represents the entire conversion value. Verify one test event with a known amount in Reddit Event Testing, even if the HTTP request succeeds.
Currency
Keep the currency input tied to the source event:
{event.properties.currency}Do not invent a fallback currency for orders that may be in another currency. Remove value and currency from mappings where no monetary value applies.
Products
The template’s products expression handles either a product array or a single-product event. Its product_id, category and name paths must match your source properties. Supply catalog IDs and categories as strings:
{event.properties.products ? arrayMap(product -> ({
'id': product.product_id,
'category': product.category,
'name': product.name
}), event.properties.products) : event.properties.product_id ? [{
'id': event.properties.product_id,
'category': event.properties.category,
'name': event.properties.name
}] : null}Item count
Add an item_count entry; it is not in the default event parameters. If your source uses these property names, map:
{event.properties.item_count ?? event.properties.quantity}For purchases, item count should reflect the total number of items in the order. For add-to-cart, it should reflect the quantity added.
Conversion ID: pair the Pixel and API
When both paths send a conversion, use the same business ID in CAPI’s conversion_id and the Pixel’s conversionId. For a purchase, use the order ID below and pass the identical string to the Pixel. This expression converts numeric IDs to strings and omits a missing ID; filter out purchases without the shared ID before sending both copies. (+)
{empty(event.properties.order_id) ? null : toString(event.properties.order_id)}The template defaults to {event.uuid}. A separately installed Pixel does not know that PostHog UUID, so keeping the default does not pair those two copies. For leads, use a lead ID or create one ID at conversion time and pass it to both paths.
Confirm both paths use the same conversion ID for the same transaction. They must also use the same event type, custom name if applicable, and channel; Pixel copies pair with CAPI WEBSITE events. Send both within two days. Deduplication runs hourly and may take up to 24 hours after both copies arrive. (+)
Never use a user ID as a conversion ID: repeat purchases or leads would reuse it, and Reddit marks events sharing an ID as duplicates, which are not attributed. More than 100 events sharing one conversion ID produces an error. (+ / +) For an API-only setup, remove conversion_id; Reddit asks you to use it only when the Pixel also sends the conversion. (+)
If you use PostHog’s Reddit Pixel destination too, inspect its browser request: that template sends conversion_id, while Reddit’s documented Pixel key is conversionId. Verify the received ID before relying on the pair. (+)
Step 9: Check every mapping
Use one Reddit destination with multiple mappings, each with its own event filters and metadata. Split destinations when credentials, consent rules or ownership differ.
- Check that each intended conversion matches its mapping and that unused defaults are gone.
- Keep purchase totals and product details on the mappings that need them; remove empty or irrelevant entries from others.
- Check that one source event cannot match two mappings that both send the same Reddit conversion.
The template sends the source event’s timestamp as event_at. Reddit accepts events only from the last seven days, so an older imported or replayed event is outside the window; changing its timestamp would change the time used for attribution. (+) The API accepts up to 1,000 events per request; this template sends one.
Step 10: Test without accidentally posting a live conversion
PostHog’s test panel makes real HTTP requests by default, and this template hard-codes test_mode: false. Running the default test can therefore post a live conversion. (+ / +)
Preview the request in PostHog
Open the test panel’s More menu and switch off Make real HTTP requests. Load a recent matching event and run the test to inspect the request PostHog would send. The HTTP call is mocked, so this preview does not prove Reddit will accept it. (+)
Validate with Reddit without recording a conversion
For a v2 validation request that posts no data to the account, click Edit source code and replace the existing let body block with this block, then allow real HTTP requests for the test: (+)
let body := {
'test_mode': true,
'events': events,
};A successful response says the events were validated but not processed. Restore test_mode to false before enabling live delivery. (+)
Inspect the event in Reddit Event Testing
To inspect the metadata and match keys in Reddit, copy your test ID from Events Manager → Event Testing. Replace the same let body block with the following, substituting your test ID. Leave test_mode false; it must not be true when using test_id:
let body := {
'test_mode': false,
'test_id': 'REPLACE_WITH_EVENT_TESTING_ID',
'events': events,
};Send the request with real HTTP requests enabled, then check the event in Event Testing: Pixel ID, type, conversion ID, match keys, currency and value should match the request. Test traffic is limited to 10 events per second and events may take up to five seconds to appear. Remove the test_id entry before live delivery. (+) Use the validation-only request when you need Reddit’s explicit guarantee that no data is posted to the account.
Use a known amount for the value check: an illustrative 10.99 USD should arrive as value_decimal: 10.99, without a second value field. Also inspect a backend event with no screen properties and an event with a masked click ID to confirm those invalid values are omitted.
Step 11: Enable and monitor the destination
Once every mapping passes, remove temporary test fields, restore test_mode: false and click Create & enable. (+)
During the first few days, compare:
- PostHog event volume.
- Reddit received event volume.
- Reddit attributed conversion volume.
- Pixel vs CAPI event overlap, if both are active.
A successful PostHog invocation confirms delivery, not a match to a Reddit user or credit for an ad. In Reddit’s Events Manager, check CAPI event activity and Diagnostics, then the event’s Match keys and Deduplication tabs. Raw event counts are before deduplication, so use the deduplication panel’s unique counts when comparing conversions. (+)
Use match-key coverage and quality recommendations to find missing or malformed identifiers; a match quality score is not proof that each event matched a person. The score needs at least 100 web events in the last seven days, and an integration change can take up to seven days to show fully. (+) Check attributed conversions separately in Ads Manager reporting, under the attribution type and window selected in Events Manager → Attribution Settings. (+)
If the gap remains unexplained, our conversion tracking audit shows how to reconcile the source conversions, received events and attributed totals.
Troubleshooting
Start with the failed request or the unexpected field, then check the matching configuration below.
| Symptom | What to check |
|---|---|
| 404 or authorization error | Copy the Pixel ID again from Events Manager into the field labelled Reddit Ads account ID, and check that the access token belongs to the business that owns the Pixel. A wrong ID can cause a 404, a member ID a 500 authorization error. (+) |
| No CAPI event appears | Check the PostHog invocation and the destination’s filters. A mocked HTTP call or test_mode: true will not add a live conversion. For test_id, look in Event Testing. |
| Unexpected events or wrong type | Remove unused default mappings, especially Page Visit, and inspect the event selected in each mapping. Step 4 lists the defaults. |
| Missing or invalid match keys | Use ip_address for the unhashed visitor IP, check email canonicalization if pre-hashing, and omit invalid screen dimensions. Check whether the person data existed when the event was processed; see the user mappings. |
| Missing or invalid click ID | Trace rdt_cid through the final landing URL and PostHog’s properties. Omit <masked> rather than forwarding it; see the click ID input. |
| Duplicated purchases or leads | Compare the conversion IDs actually received from each path and check for overlapping PostHog mappings. Apply the conversion ID pairing rules before judging deduplication. |
| Wrong revenue or currency | Check base units versus minor units, order total versus item price, gross versus net, and the source currency. Use the v2 value mapping. |
| Missing products or catalog mismatch | Inspect the source product array, required category and variant ID. The destination cannot supply product data absent from PostHog; see the product expression. |
| Old event rejected | Compare the source timestamp with the seven-day limit. Do not replace it with today’s time to make a backfill pass. |
Frequently asked questions
Why does Reddit show fewer conversions than PostHog?
Because an accepted event still needs to match a person and qualify for ad attribution. By default, Reddit uses 28 days for click-through attribution and one day for view-through attribution. (+) Reddit reports conversions against the date of the ad interaction, which can differ from the conversion date you use in PostHog. Compare the same conversion definition, date range and time zone before treating the difference as a delivery failure. (+)
Can I send custom conversion events?
Should I multiply revenue by 100?
Only if you choose v2 value and the currency has two decimal places. With value_decimal, send the base-unit amount without multiplying. An illustrative USD purchase of 10.99 can be value_decimal: 10.99 or value: 1099, never both. Do not assume every currency has two decimal places. (+)
Does PostHog’s destination test send a real Reddit conversion?
Why is rdt_cid missing from PostHog?
It may never have reached the page where PostHog captured the event. Follow a Reddit ad click through every redirect and inspect the final URL; a visitor who did not click a Reddit ad will not bring that click ID. (+) If it exists on the event but not the person, check identification timing: anonymous events do not update person properties under the default configuration. (+)
