Skip to main content

Reddit Conversions API

Server Source code Package Beta

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.

Where this fits

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
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',
      },
    },
  },
},
});

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

PropertyTypeDescriptionMore
accessToken*stringReddit Conversion Access Token for Bearer authentication
pixelId*stringReddit Pixel ID used as the API path parameter
action_sourceSource of the event (WEBSITE, APP, PHYSICAL_STORE)
doNotHashArray<string>Array of user fields that should not be hashed
test_modebooleanEnable test mode by sending test_mode: true in the request body
urlstringCustom URL for Reddit Conversions API endpoint
user_dataRecord<string, string>Mapping configuration for user fields
* Required 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.

Event
{
  "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"
  }
}
Mapping
{
  "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"
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "name": "Lead",
  "data": {
    "map": {
      "user": {
        "map": {
          "email": "user.email",
          "external_id": "user.id"
        }
      }
    }
  }
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "name": "PageVisit"
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "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"
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "name": "Search",
  "data": {
    "map": {
      "event_metadata": {
        "map": {
          "item_count": {
            "value": 1
          }
        }
      }
    }
  }
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "name": "SignUp",
  "data": {
    "map": {
      "user": {
        "map": {
          "email": "user.email",
          "external_id": "user.id"
        }
      }
    }
  }
}
Out
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 EventReddit tracking_type
page viewPageVisit
product viewViewContent
site searchSearch
product addAddToCart
product wishlistAddToWishlist
order completePurchase
form submitLead
user signupSignUp

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.

Different from Meta/Pinterest

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
}
💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)