Why Snapchat CAPI
Snapchat is still one of the most direct paid social channels for younger shoppers, and its 14+ demographic matters for DTC beauty, fashion, gaming, entertainment, accessories, and app-adjacent commerce. Those verticals often have fast discovery loops, high mobile traffic, and short product consideration windows. A user might swipe up from an ad, browse a product, leave, return through a saved cart link, and purchase after a payment redirect. When the browser is the only source of truth, every one of those steps can weaken attribution.
Snapchat's 7-day click attribution is especially hurt by Safari ITP because Safari shortens or blocks the browser state that paid media platforms use to connect the ad click with the later conversion. Ad blockers, privacy extensions, checkout subdomains, embedded wallets, and consent changes add more gaps. CAPI does not bypass privacy choices, and it does not make weak campaigns perform better by itself. It gives Snap a cleaner server-side event, attached to the same event_id, URL, click identifier, and permitted first-party signals that your business already collected.
Prerequisites
Snap Business Manager access with permission to manage the ad account, Snap Pixel, catalogs, domains, and Events Manager diagnostics.
pixel_id for the production Snap Pixel connected to the ad account that will optimize campaigns from these events.
A long-lived access token with Conversions API permission, stored as an encrypted server secret and rotated through your normal credential process.
A verified domain covering the shop, landing pages, checkout domain, and any regional hostnames used by paid Snapchat traffic.
Step-by-step setup
Confirm the Pixel and event taxonomy
Start in Snap Events Manager and confirm that the Pixel belongs to the same business, ad account, catalog, and verified domain used by live campaigns. Align event names before writing server code. PAGE_VIEW, VIEW_CONTENT, ADD_CART, START_CHECKOUT, PURCHASE, SIGN_UP, and CUSTOM_EVENT should mean the same thing in Pixel, CAPI, analytics, and order logs.
POST https://tr.snapchat.com/v3/{pixel_id}/events
Authorization: Bearer SNAP_LONG_LIVED_ACCESS_TOKEN
Content-Type: application/json
{
"data": []
}Capture browser context at the first request
The server often receives the order after the browser has changed context. Capture sc_click_id from the landing URL, scid from Snap's first-party cookie when available, the current URL, user agent, IP address, event_id, and consent state before checkout redirects or payment pages can strip them.
{
"data": [
{
"event_name": "ADD_CART",
"event_time": 1776943226,
"event_id": "cart_10492_add_1",
"event_source_url": "https://shop.example/products/lip-oil",
"user_data": {
"sc_click_id": "b7f4a9d0-6a8f-4c5d...",
"client_ip_address": "203.0.113.42",
"client_user_agent": "Mozilla/5.0..."
},
"custom_data": {
"value": 39.95,
"currency": "EUR",
"item_ids": ["SKU-481"],
"item_category": "beauty"
}
}
]
}Normalize identifiers before hashing
Snap can use deterministic first-party identifiers when consent allows. Lowercase and trim email, convert phone to a stable E.164-style format, and hash email, phone, and external_id with SHA-256 unless your tracking layer performs that transformation. Do not hash sc_click_id, scid, IP address, user agent, or mobile advertising IDs.
{
"data": [
{
"event_name": "START_CHECKOUT",
"event_time": 1776943312,
"event_id": "chk_10492_start",
"event_source_url": "https://shop.example/checkout",
"user_data": {
"em": ["sha256_lowercase_email"],
"ph": ["sha256_e164_phone"],
"external_id": ["sha256_customer_id"],
"sc_click_id": "b7f4a9d0-6a8f-4c5d...",
"client_ip_address": "203.0.113.42",
"client_user_agent": "Mozilla/5.0..."
}
}
]
}Send purchase truth from the backend
For PURCHASE events, use the order system as the source of truth. Send value as a number, currency as a three-letter ISO code, and item_ids that match the catalog IDs used by Snapchat Dynamic Ads. Decide whether value includes tax, shipping, discounts, and refunds before launch, then keep that policy consistent in media and finance reporting.
{
"data": [
{
"event_name": "PURCHASE",
"event_time": 1776943380,
"event_id": "ord_10492_purchase",
"event_source_url": "https://shop.example/order-confirmation",
"user_data": {
"em": ["sha256_lowercase_email"],
"ph": ["sha256_e164_phone"],
"sc_click_id": "b7f4a9d0-6a8f-4c5d...",
"client_ip_address": "203.0.113.42",
"client_user_agent": "Mozilla/5.0..."
},
"custom_data": {
"value": 129.95,
"currency": "EUR",
"item_ids": ["SKU-481", "SKU-812"],
"item_category": "beauty"
}
}
]
}Log responses and retry idempotently
Treat Snapchat CAPI like revenue infrastructure. Store pixel_id, event_id, consent decision, identifiers present, response status, request ID, and retry count. Retry network failures with backoff, but do not replay an accepted purchase with a new event_id. That creates duplicate conversion candidates and makes Events Manager diagnostics harder to trust.
{
"data": [
{
"event_name": "SIGN_UP",
"event_time": 1776943445,
"event_id": "lead_77821_submit",
"event_source_url": "https://shop.example/quiz",
"user_data": {
"em": ["sha256_lowercase_email"],
"sc_click_id": "b7f4a9d0-6a8f-4c5d...",
"client_ip_address": "203.0.113.42",
"client_user_agent": "Mozilla/5.0..."
}
}
]
}Required fields
Snapchat can accept sparse events, but sparse events give the platform little to match, deduplicate, or optimize. Use this table as the minimum production contract for web commerce, lead, and checkout events. The key is consistency: event_name, event_id, event_time, value, currency, and item_ids should mean the same thing in Snap Pixel, CAPI, analytics, and backend logs.
| Field | Required | Purpose | Example |
|---|---|---|---|
| event_name | Yes | Names the conversion action Snapchat should process. | PURCHASE |
| event_source_url | Recommended | The page URL where the action happened or was confirmed. | https://shop.example/order-confirmation |
| event_time | Yes | Unix timestamp in seconds from the actual event moment. | 1776943380 |
| event_id | Recommended | Deduplicates matching Snap Pixel and CAPI events. | ord_10492_purchase |
| user_data.em | Recommended | SHA-256 hashed normalized email for deterministic matching. | ["6b3a55e0261b..."] |
| user_data.ph | Recommended | SHA-256 hashed normalized phone number. | ["b49f9168e8a8..."] |
| user_data.sc_click_id | Recommended | Snapchat click identifier from paid traffic landing URLs. | b7f4a9d0-6a8f-4c5d... |
| user_data.client_ip_address | Recommended | Client IP address from the shopper request. | 203.0.113.42 |
| user_data.client_user_agent | Recommended | Browser and device context paired with the event. | Mozilla/5.0... |
| user_data.external_id | Recommended | SHA-256 hashed stable customer, lead, or account identifier. | ["sha256_cust_34982"] |
| user_data.madid | App events | Mobile advertising ID for eligible app or app-web journeys. | AEBE52E7-03EE-455A-B3C4... |
| custom_data.value | For purchases | Revenue value used for reporting and optimization. | 129.95 |
| custom_data.currency | For purchases | ISO 4217 currency code for the value field. | EUR |
| custom_data.item_ids | Recommended | Catalog or SKU IDs associated with the conversion. | ["SKU-481"] |
| custom_data.item_category | Recommended | Product category context for optimization and diagnostics. | beauty |
The sc_click_id + scid cookies
sc_click_id is Snapchat's paid-click identifier. It usually appears on the landing URL after a user swipes up or taps through from an ad. scid is the related first-party browser value that Snap Pixel may use to keep session context alive on the site. They are not replacements for hashed email or phone, but they help connect a server event with the ad interaction that created the visit.
Safari ITP makes this fragile. Query parameters can be lost after redirects, first-party cookies can have short lifetimes, and checkout domains may not share browser storage with the original landing page. Capture sc_click_id from the URL on the first page view, read scid from the browser when it exists, and attach those values to the cart, checkout, or lead record. If the purchase is created later by a webhook, the webhook should read the stored click context instead of trying to recover it from the browser.
function readSnapContext() {
const params = new URLSearchParams(window.location.search);
const scClickId = params.get("sc_click_id");
const scid = document.cookie
.split("; ")
.find((part) => part.startsWith("_scid="))
?.split("=")[1];
return {
sc_click_id: scClickId || null,
scid: scid || null,
user_agent: navigator.userAgent
};
}
await fetch("/api/cart/context", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(readSnapContext())
});Dedup with Pixel
Deduplication prevents Snap Pixel and CAPI from turning one user action into two conversion candidates. Generate one event_id for each meaningful action, pass it to the browser Pixel call, and send the same value in the CAPI payload. Good IDs are unique per action, stable across retries, readable in logs, and derived from the entity that created the event: cart_10492_add_1, chk_10492_start, or ord_10492_purchase.
const eventId = "ord_10492_purchase";
snaptr("track", "PURCHASE", {
event_id: eventId,
price: 129.95,
currency: "EUR",
item_ids: ["SKU-481", "SKU-812"]
});
await fetch("/api/tracklayer/snapchat-capi", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
event_name: "PURCHASE",
event_time: Math.floor(Date.now() / 1000),
event_id: eventId,
event_source_url: window.location.href,
user_data: {
em: [sha256(normalizeEmail(customer.email))],
sc_click_id: readSnapContext().sc_click_id,
client_user_agent: navigator.userAgent
},
custom_data: {
value: 129.95,
currency: "EUR",
item_ids: ["SKU-481", "SKU-812"],
item_category: "beauty"
}
})
});Testing with Events Manager
Send a controlled browser journey
Open a Snapchat-style landing URL with sc_click_id, trigger PAGE_VIEW, ADD_CART, START_CHECKOUT, and PURCHASE, then confirm the server event keeps the same event_id and URL context.
Compare Pixel and CAPI pairs
In Events Manager, inspect matching browser and server events. The event_name and event_id should line up, while CAPI should carry stronger user_data from checkout or order records.
Review Events Quality Indicator
Use Snapchat's Events Quality Indicator to find weak match keys, missing click identifiers, stale timestamps, domain mismatches, invalid value fields, or consent-related suppression.
Consent Mode handling
Snapchat should receive the same consent decision that governs the browser Pixel. When ad_user_data is denied, your server route should remove personal identifiers such as hashed email, hashed phone, external_id, and madid before dispatch, or suppress the destination entirely if that is what your regional policy requires. A denied signal is not a formatting issue; it is an instruction about which data can be used for advertising.
A durable pattern is to capture consent at event collection time, store it in the event envelope, and evaluate Snapchat rules just before sending. That lets you keep internal analytics, fulfillment, or fraud events while withholding Snapchat user_data when the user has denied ad_user_data. Keep the Pixel and CAPI behavior symmetrical so a denied browser event does not quietly reappear from the server with stronger identifiers.
Troubleshooting
401 unauthorized token
Regenerate the long-lived access token from the correct Snap Business Manager, confirm CAPI permission, and verify the token can access the target pixel_id.
Events accepted but not attributed
Check sc_click_id capture, domain verification, event_time freshness, and whether the conversion happened inside Snapchat's attribution window for the campaign.
Duplicate purchase warnings
Generate event_id once per action and reuse it for both Snap Pixel and CAPI. Do not create a new server-only ID for the same purchase.
Low Events Quality Indicator score
Add hashed email or phone where consent allows, preserve sc_click_id or scid, and forward client IP plus user agent from the original browser request.
Invalid custom_data format
Send value as a number, currency as an ISO code, and item_ids that exactly match the product IDs in the Snapchat catalog feed.
Common questions
Can Snapchat CAPI replace the Snap Pixel?
For most web advertisers, no. Pixel captures browser context, click state, and immediate site behavior. CAPI strengthens delivery for checkout, lead, and purchase events by sending the same user action from a more reliable server source.
Which Snapchat events should ecommerce stores send?
Start with PAGE_VIEW, VIEW_CONTENT, ADD_CART, START_CHECKOUT, and PURCHASE. Add SIGN_UP, SEARCH, or CUSTOM_EVENT only when those actions are important enough for campaign optimization or audience building.
Do I need sc_click_id on every event?
No. Direct, organic, and some returning sessions will not have it. For paid Snapchat sessions, preserving sc_click_id is high value because it ties the server event back to the ad click that started the journey.
Should I hash sc_click_id or scid?
No. Hash personal identifiers such as email, phone, and external_id after normalization. Send sc_click_id, scid, IP address, user agent, and eligible mobile ad IDs in the native format Snapchat expects.
How quickly should Events Quality Indicator improve?
Field-level diagnostics can improve after a small number of accepted events, but a stable quality signal usually needs normal traffic volume across several hours or days. Low-volume stores should judge trends rather than single test events.
Related implementation guides
TikTok Events API guide
Build TikTok server events with ttclid, ttp, event_id, consent handling, and Event Match Quality checks.
Read guide →Meta CAPI setup guide
Compare Snapchat CAPI with Meta CAPI, including deduplication, user_data, and Events Manager diagnostics.
Read guide →Deduplication explained
How browser and server events become one conversion across paid media platforms.
Read guide →