Why Reddit CAPI
Reddit is still underpriced for a specific class of advertisers: B2B tech teams selling into technical buyers, gaming publishers with community-led demand, crypto and fintech brands that need credible discussion instead of polished ad inventory, and DTC companies built around niche hobbies. The platform is not always the easiest place to scale broad prospecting, but it can surface buyers who are already reading threads, comparing tools, and asking blunt questions before they ever search for a brand.
That behavior makes measurement fragile. A Reddit click can land on a long technical article, send the user into docs, return through a direct visit, and convert after a sales form, checkout, or app install handoff. Browser-only tracking loses pieces of that path through ad blockers, Safari restrictions, consent banners, payment redirects, and cross-device research. Reddit Conversions API gives your server a direct way to send the final conversion with the first-party context you were allowed to keep.
Prerequisites
Reddit Ads account with admin or measurement access to the ad account that owns the conversion source.
pixel_id from Reddit Events Manager for the production website pixel, not a staging or agency-only test pixel.
conversion_access_token generated from Reddit Ads Manager with permission to send conversion events for the target ad account.
Domain verified in Reddit Ads Manager for the landing pages, checkout domain, and any embedded storefront path used by paid traffic.
Step-by-step setup
Build the integration in narrow layers: prove authorization, add browser context, normalize identifiers, send backend truth, then harden logging and retries. Each layer should be independently visible in your logs and Reddit diagnostics.
Confirm account, pixel, and token ownership
Start with the objects that route the event. Reddit CAPI is scoped to an ad account endpoint, while the payload references a pixel_id and the request is authorized by the conversion_access_token. A token can be valid and still be useless if it belongs to a different business, account, or pixel. Make your first request intentionally small so token scope, account ownership, and endpoint formatting are the only variables.
POST https://ads-api.reddit.com/api/v2.0/conversions/events/{ad_account_id}
Authorization: Bearer conversion_access_token
Content-Type: application/json
{
"pixel_id": "t2_abc123",
"event_at": "2026-04-23T10:15:30.000Z",
"event_type": {
"tracking_type": "PageVisit"
},
"event_metadata": {
"conversion_id": "pv_session_10492_1"
},
"user": {
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0..."
}
}Capture browser context before checkout
The backend needs values that only the browser sees at landing time. Capture the Reddit click identifiers, client IP, user agent, screen dimensions, consent state, and product context before a payment redirect or embedded checkout changes domains. Store those values against the session, cart, or checkout so the purchase event can reuse the original context.
{
"pixel_id": "t2_abc123",
"event_at": "2026-04-23T10:18:22.000Z",
"event_type": {
"tracking_type": "AddToCart"
},
"event_metadata": {
"value": 89.95,
"currency": "USD",
"item_count": 1,
"conversion_id": "cart_10492_add_1"
},
"user": {
"email": "sha256_lowercase_email",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0...",
"screen_dimensions": {
"width": 1440,
"height": 900
}
}
}Normalize user identifiers before hashing
Reddit can use deterministic first-party identifiers when consent and policy allow them. Normalize email by trimming and lowercasing before SHA-256 hashing. Normalize external_id to your stable customer or lead ID format, then hash it if your policy requires hashed transmission. Do not hash IP address, user agent, device advertising IDs, or screen dimensions because those fields are expected in their native formats.
import crypto from "node:crypto";
function sha256(value: string) {
return crypto
.createHash("sha256")
.update(value.trim().toLowerCase())
.digest("hex");
}
const user = {
email: sha256("buyer@example.com"),
external_id: sha256("cust_10492"),
ip_address: "203.0.113.42",
user_agent: "Mozilla/5.0..."
};Send purchase truth from the backend
For Purchase, Lead, SignUp, and other lower-funnel actions, use the system of record as the event source. The order service should decide final value, currency, item_count, conversion_id, timestamp, refund policy, and whether the event is eligible for Reddit. Avoid letting a browser confirmation page become the only source of revenue truth.
{
"pixel_id": "t2_abc123",
"event_at": "2026-04-23T10:24:16.000Z",
"event_type": {
"tracking_type": "Purchase"
},
"event_metadata": {
"value": 129.95,
"currency": "USD",
"item_count": 2,
"conversion_id": "ord_10492_purchase"
},
"user": {
"email": "sha256_lowercase_email",
"external_id": "sha256_customer_id",
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0...",
"screen_dimensions": {
"width": 1440,
"height": 900
}
}
}Log responses and retry with the same conversion_id
Operate Reddit CAPI like revenue infrastructure. Store the request body, response status, response ID if present, conversion_id, token version, consent decision, identifiers present, and retry count. Retry transient network failures with backoff, but keep the same conversion_id. Replaying a purchase with a new ID makes diagnostics harder and can produce duplicate conversion candidates.
{
"event": "reddit_capi_dispatch",
"ad_account_id": "a2_abc123",
"pixel_id": "t2_abc123",
"tracking_type": "Purchase",
"conversion_id": "ord_10492_purchase",
"status": 200,
"retry_count": 0,
"identifiers_present": ["email", "ip_address", "user_agent", "rdt_uuid"]
}Required fields
Reddit will not need every field on every event, but production payloads should be predictable. The table below is the practical contract for web and app events. Keep the same meanings across Reddit Pixel, CAPI, analytics, and backend logs so a rejected or duplicated conversion can be traced without guesswork.
| Field | Type | Required | Purpose | Example |
|---|---|---|---|---|
| event_at | ISO string | Yes | Timestamp for when the conversion actually happened, not when a queue worker sent it. | 2026-04-23T10:24:16.000Z |
| event_type.tracking_type | string | Yes | Reddit event name used for optimization and reporting. | Purchase |
| event_metadata.value | number | For purchases | Revenue value used in reporting and bidding signals. | 129.95 |
| event_metadata.currency | string | For value | Three-letter ISO 4217 currency code. | USD |
| event_metadata.item_count | number | Recommended | Count of items associated with the conversion. | 2 |
| event_metadata.conversion_id | string | Recommended | Stable deduplication key shared by Reddit Pixel and CAPI. | ord_10492_purchase |
| user.email | sha256 string | Recommended | Hashed normalized email for deterministic matching. | 6b3a55e0261b... |
| user.external_id | string | Recommended | Stable customer, lead, or account identifier when available. | sha256_customer_id |
| user.ip_address | string | Recommended | Client IP address from the browser request. | 203.0.113.42 |
| user.user_agent | string | Recommended | Browser and device context used for validation and matching. | Mozilla/5.0... |
| user.aaid | string | App traffic | Android advertising ID for eligible app events. | cdda802e-fb9c-47ad-9866-0794d394c912 |
| user.idfa | string | App traffic | Apple advertising ID when ATT and consent allow it. | 7D9B2B40-5E4D-4A25-A0F0-5A6C7E8D9012 |
| user.screen_dimensions | object | Recommended | Client viewport context with width and height. | { width: 1440, height: 900 } |
The rdt_uuid + _reddit_uuid2 cookies
Reddit's click and browser identifiers are the bridge between an ad interaction and a later server event. The Reddit Pixel can write first-party cookie values such as rdt_uuid and _reddit_uuid2 on your domain. When present, those values help Reddit connect CAPI events to the browser session that saw or clicked an ad. They are especially useful when the conversion happens after checkout moves to another domain or when the purchase is finalized by a backend webhook.
Capture these cookies early and attach them to the session or cart. Send the original values as context in your server event or internal dispatch envelope, depending on the exact connector you use. Do not fabricate them, do not hash them, and do not treat them as a replacement for eligible first-party identifiers like hashed email. They are strongest when paired with IP address, user agent, screen dimensions, and a stable conversion_id.
function readCookie(name: string) {
return document.cookie
.split("; ")
.find((part) => part.startsWith(name + "="))
?.split("=")[1] || null;
}
await fetch("/api/cart/reddit-context", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
rdt_uuid: readCookie("rdt_uuid"),
reddit_uuid2: readCookie("_reddit_uuid2"),
user_agent: navigator.userAgent,
screen_dimensions: {
width: window.screen.width,
height: window.screen.height
}
})
});Dedup with Pixel
Deduplication prevents Reddit Pixel and CAPI from turning one action into two conversions. Generate one conversion_id per meaningful action, pass it to the browser event, and reuse the same value in the server payload. A readable convention is entity_action_result: cart_10492_add, lead_77821_submit, or ord_10492_purchase. The ID should be unique per action, stable across retries, and visible in diagnostics.
const conversionId = "ord_10492_purchase";
rdt("track", "Purchase", {
conversionId,
value: 129.95,
currency: "USD",
itemCount: 2
});
await fetch("/api/tracklayer/reddit-capi", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
event_at: new Date().toISOString(),
event_type: {
tracking_type: "Purchase"
},
event_metadata: {
value: 129.95,
currency: "USD",
item_count: 2,
conversion_id: conversionId
},
user: {
email: sha256(normalizeEmail(customer.email)),
ip_address: requestClientIp,
user_agent: navigator.userAgent
}
})
});Testing with Events Manager
Send one known browser and server pair
Trigger a Reddit Pixel event and a CAPI event from the same session with the same tracking_type and conversion_id. Use a realistic landing URL, consent state, user agent, and order value.
Inspect Events Manager diagnostics
Confirm the event reaches the correct pixel and ad account. Review rejected fields, token errors, stale timestamps, malformed metadata, missing identifiers, and domain verification warnings.
Compare reporting after processing
Wait for Reddit processing before judging attribution. API acceptance proves delivery, while reporting needs matching, deduplication, attribution window eligibility, and campaign activity.
Consent Mode handling
Reddit's EU consent handling is more limited than Google Consent Mode, so do not assume the platform can model around a denied signal in the same way. Your tracking layer should decide whether Reddit receives the event, which identifiers are removed, and whether browser Pixel and server CAPI are treated symmetrically. If advertising storage or ad measurement is denied, suppressing the destination is often cleaner than sending a nearly anonymous purchase that your legal and media teams interpret differently.
A durable pattern is to capture consent at the event edge, store it with the order or lead event, and evaluate Reddit routing just before dispatch. Internal analytics can still retain operational purchase truth, while Reddit receives only events and identifiers that match the user's region, CMP decision, and your policy.
Troubleshooting
401 or 403 authentication errors
Regenerate the conversion_access_token from Reddit Ads Manager and confirm it has access to the ad account in the endpoint and the pixel_id in the payload.
Events accepted but not visible
Check pixel_id ownership, domain verification, event_at freshness, processing delay, and whether you are looking at the same ad account used in the API path.
Duplicate purchases
Generate conversion_id once per action and reuse it for both Pixel and CAPI. Do not let the browser, backend, and retry job mint different IDs.
Low match or attribution quality
Preserve rdt_uuid and _reddit_uuid2, add permitted email or external_id, forward the true client IP and user agent, and suppress placeholder identifiers.
Invalid event metadata
Send value as a number, currency as an ISO code, item_count as a number, and tracking_type as one of Reddit's supported event names.
Common questions
Can Reddit CAPI replace the Reddit Pixel?
Usually no. The Pixel captures browser context, retargeting audiences, and immediate interaction signals. CAPI strengthens delivery and conversion truth, especially after redirects or blockers. The most reliable setup runs both and deduplicates them.
Which event types should I start with?
Start with PageVisit, ViewContent, AddToCart, Lead, SignUp, and Purchase if those actions exist on your site. Avoid sending low-quality backend noise until the lower-funnel events are accepted and deduplicated.
Do I need both rdt_uuid and _reddit_uuid2?
Capture both when present because cookie behavior can vary by Reddit Pixel version, browser state, and traffic source. Do not invent these values. If the cookies are absent, send other eligible identifiers and context.
Should I hash IP address or user agent?
No. Hash normalized personal identifiers such as email when required. Send IP address, user agent, device advertising IDs, click identifiers, and screen dimensions in the format Reddit expects.
How long should I keep event logs?
Keep enough history to diagnose attribution and replay failures across your refund, attribution, and reporting windows. For most teams, 30 to 90 days of request and response logs is the minimum useful range.
Related implementation guides
TikTok Events API
Build TikTok server events with ttclid, ttp, event_id, consent-aware forwarding, and Events Manager validation.
Read guide →Pinterest Conversions API
Compare Reddit CAPI with Pinterest CAPI, including click identifiers, match quality, deduplication, and consent routing.
Read guide →Deduplication explained
How browser and server events become one conversion across paid media platforms.
Read guide →