Reddit Conversions API
Server-side event delivery to Reddit's Conversions API v2.0 for enhanced conversion tracking, bypassing browser limitations and improving match quality for ad optimization.
Reddit Conversions API is a server destination in the walkerOS flow:
Sends events server-side to Reddit's Conversions API using raw HTTP (no SDK). Identity fields (`email`, `external_id`, `ip_address`, `user_agent`, `idfa`, `aaid`) are SHA-256 hashed before sending. Events include a stable `event_metadata.conversion_id` for deduplication with the Reddit Pixel.
Installation
npm install @walkeros/server-destination-reddit- Integrated
- Bundled
import { startFlow } from '@walkeros/collector';
import { destinationReddit } from '@walkeros/server-destination-reddit';
await startFlow({
destinations: {
reddit: {
code: destinationReddit,
config: {
settings: {
accessToken: 'YOUR_ACCESS_TOKEN',
pixelId: 'YOUR_PIXEL_ID',
},
},
},
},
});Add to your flow.json destinations:
"destinations": {
"reddit": {
"package": "@walkeros/server-destination-reddit",
"import": "destinationReddit",
"config": {
"settings": {
"accessToken": "YOUR_ACCESS_TOKEN",
"pixelId": "YOUR_PIXEL_ID"
}
}
}
}Configuration
This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see destination configuration. Package-specific fields live under config.settings and are listed below.
Settings
| Property | Type | Description | More |
|---|---|---|---|
accessToken | string | Reddit Conversion Access Token for Bearer authentication | |
pixelId | string | Reddit Pixel ID used as the API path parameter | |
action_source | Source of the event (WEBSITE, APP, PHYSICAL_STORE) | ||
doNotHash | Array<string> | Array of user fields that should not be hashed | |
test_mode | boolean | Enable test mode by sending test_mode: true in the request body | |
url | string | Custom URL for Reddit Conversions API endpoint | |
user_data | Record<string, string> | Mapping configuration for user fields |
Mapping
This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
Examples
Add to cart
A product add is sent to Reddit as an AddToCart conversion with value and product details.
{
"name": "product add",
"data": {
"id": "SKU-B2",
"name": "Cool Cap",
"category": "hats",
"price": "42.00",
"quantity": 1
},
"context": {
"shopping": [
"intent",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "user-456"
},
"nested": [],
"consent": {
"functional": true
},
"id": "ev-1700000901",
"trigger": "click",
"entity": "product",
"action": "add",
"timestamp": 1700000901,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "AddToCart",
"data": {
"map": {
"event_metadata": {
"map": {
"value_decimal": "data.price",
"currency": {
"value": "EUR"
},
"item_count": {
"value": 1
},
"products": {
"set": [
{
"map": {
"id": "data.id",
"name": "data.name",
"category": {
"key": "data.category",
"value": "uncategorized"
}
}
}
]
}
}
}
}
}
}sendServer("https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456", "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.901Z\",\"event_at_ms\":1700000901,\"event_type\":{\"tracking_type\":\"AddToCart\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"ev-1700000901\",\"value_decimal\":\"42.00\",\"currency\":\"EUR\",\"item_count\":1,\"products\":[{\"id\":\"SKU-B2\",\"name\":\"Cool Cap\",\"category\":\"hats\"}]}}]}}", {
"headers": {
"Authorization": "Bearer s3cr3t"
}
})Lead
A form submission is sent to Reddit as a Lead conversion with the SHA-256 hashed email and external id.
{
"name": "form submit",
"data": {
"form": "contact"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "user-lead-1",
"email": "lead@example.com"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "ev-1700000903",
"trigger": "test",
"entity": "form",
"action": "submit",
"timestamp": 1700000903,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "Lead",
"data": {
"map": {
"user": {
"map": {
"email": "user.email",
"external_id": "user.id"
}
}
}
}
}sendServer("https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456", "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.903Z\",\"event_at_ms\":1700000903,\"event_type\":{\"tracking_type\":\"Lead\"},\"user\":{\"email\":\"9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2\",\"external_id\":\"ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8\"},\"event_metadata\":{\"conversion_id\":\"ev-1700000903\"}}]}}", {
"headers": {
"Authorization": "Bearer s3cr3t"
}
})Page visit
A page view is sent to Reddit as a PageVisit conversion used for retargeting audiences.
{
"name": "page view",
"data": {
"domain": "www.example.com",
"title": "walkerOS documentation",
"referrer": "https://www.walkeros.io/",
"search": "?foo=bar",
"hash": "#hash",
"id": "/docs/"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"pagegroup": "docs"
},
"custom": {
"completely": "random"
},
"user": {
"id": "user-789"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "ev-1700000902",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000902,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "PageVisit"
}sendServer("https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456", "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.902Z\",\"event_at_ms\":1700000902,\"event_type\":{\"tracking_type\":\"PageVisit\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"ev-1700000902\"}}]}}", {
"headers": {
"Authorization": "Bearer s3cr3t"
}
})Purchase
A completed order is sent to the Reddit Conversions API as a Purchase event with value, currency, and items.
{
"name": "order complete",
"data": {
"id": "ORD-300",
"total": 249.99,
"currency": "EUR"
},
"context": {
"shopping": [
"complete",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "user-123",
"device": "device-456"
},
"nested": [
{
"entity": "product",
"data": {
"id": "SKU-A1",
"name": "Everyday Ruck Snack",
"category": "bags",
"price": "129.99",
"quantity": 2
}
}
],
"consent": {
"functional": true
},
"id": "ev-1700000900",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000900,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "Purchase",
"data": {
"map": {
"event_metadata": {
"map": {
"value_decimal": "data.total",
"currency": {
"key": "data.currency",
"value": "EUR"
},
"item_count": {
"fn": {
"$code": "e=>e.nested.filter(e=>\"product\"===e.entity).length"
}
},
"products": {
"loop": [
"nested",
{
"condition": {
"$code": "e=>h(e)&&\"product\"===e.entity"
},
"map": {
"id": "data.id",
"name": "data.name",
"category": {
"key": "data.category",
"value": "uncategorized"
}
}
}
]
}
}
}
}
}
}sendServer("https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456", "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.900Z\",\"event_at_ms\":1700000900,\"event_type\":{\"tracking_type\":\"Purchase\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"ev-1700000900\",\"value_decimal\":249.99,\"currency\":\"EUR\",\"item_count\":1,\"products\":[{\"id\":\"SKU-A1\",\"name\":\"Everyday Ruck Snack\",\"category\":\"bags\"}]}}]}}", {
"headers": {
"Authorization": "Bearer s3cr3t"
}
})Search
A site search is sent to Reddit as a Search conversion with an item count in event_metadata.
{
"name": "site search",
"data": {
"query": "walkerOS destinations"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "user-101"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "ev-1700000905",
"trigger": "test",
"entity": "site",
"action": "search",
"timestamp": 1700000905,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "Search",
"data": {
"map": {
"event_metadata": {
"map": {
"item_count": {
"value": 1
}
}
}
}
}
}sendServer("https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456", "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.905Z\",\"event_at_ms\":1700000905,\"event_type\":{\"tracking_type\":\"Search\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"ev-1700000905\",\"item_count\":1}}]}}", {
"headers": {
"Authorization": "Bearer s3cr3t"
}
})Sign up
A user signup is sent to Reddit as a SignUp conversion with hashed user identifiers.
{
"name": "user signup",
"data": {
"method": "email"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "new-user-1",
"email": "new@example.com"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "ev-1700000904",
"trigger": "test",
"entity": "user",
"action": "signup",
"timestamp": 1700000904,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "express",
"platform": "server"
}
}{
"name": "SignUp",
"data": {
"map": {
"user": {
"map": {
"email": "user.email",
"external_id": "user.id"
}
}
}
}
}sendServer("https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456", "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.904Z\",\"event_at_ms\":1700000904,\"event_type\":{\"tracking_type\":\"SignUp\"},\"user\":{\"email\":\"f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716\",\"external_id\":\"b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde\"},\"event_metadata\":{\"conversion_id\":\"ev-1700000904\"}}]}}", {
"headers": {
"Authorization": "Bearer s3cr3t"
}
})Event mapping
Reddit uses a rigid taxonomy. Map walkerOS events to a standard tracking_type via each rule's name field:
| walkerOS Event | Reddit tracking_type |
|---|---|
page view | PageVisit |
product view | ViewContent |
site search | Search |
product add | AddToCart |
product wishlist | AddToWishlist |
order complete | Purchase |
form submit | Lead |
user signup | SignUp |
Any non-standard name becomes { tracking_type: 'Custom', custom_event_name: '<name>' } automatically. Reddit's AI optimization is trained on the standard events, so prefer them when possible.
"mapping": {
"order": {
"complete": {
"name": "Purchase",
"data": {
"map": {
"event_metadata": {
"map": {
"value_decimal": "data.total",
"currency": "data.currency",
"item_count": { "value": 1 }
}
}
}
}
}
}
}event_metadata structure
Unlike Meta's CAPI (which uses custom_data) and Pinterest (which also uses custom_data), Reddit places conversion details under event_metadata. Always map into event_metadata.map. Products belong in event_metadata.products[] with { id, name?, category }.
Payload envelope
Reddit wraps events inside { data: { events: [...] } } (nested), unlike Meta/Pinterest's flat { data: [...] }. The destination handles this automatically.
Hashing
The destination automatically SHA-256 hashes the 6 standard identity fields before sending: email, external_id, ip_address, user_agent, idfa, aaid. Pass raw values and hashing is handled for you.
Reddit hashes ip_address and user_agent, which Meta CAPI and Pinterest CAPI pass through as plaintext. Be sure to pass the raw values, not pre-hashed ones, unless you use doNotHash.
Non-hashable fields pass through as-is: uuid, opt_out, screen_dimensions, data_processing_options.
If a value is already hashed or you want to skip hashing for a specific field, use doNotHash:
"settings": {
"accessToken": "YOUR_ACCESS_TOKEN",
"pixelId": "YOUR_PIXEL_ID",
"doNotHash": ["email"]
}Deduplication
Each event is sent with event_metadata.conversion_id set to the walkerOS event id. If you also run the Reddit Pixel in the browser, Reddit deduplicates server and browser events that share the same conversion_id, so conversions are not double-counted.
Test mode
Set test_mode: true in settings to send "test_mode": true as a top-level boolean in the request body (not a query parameter, unlike Pinterest). Useful during development.
"settings": {
"accessToken": "YOUR_ACCESS_TOKEN",
"pixelId": "YOUR_PIXEL_ID",
"test_mode": true
}