TikTok Pixel vs Events API
TikTok Pixel is the browser-side instrument. It loads on the page, observes user actions, reads browser context, stores the _ttp cookie, sees the ttclid click parameter when a user lands from a TikTok ad, and can fire immediately when someone views a product, adds an item to cart, submits a lead form, or reaches checkout. That proximity is valuable because the browser knows the session. It also makes Pixel vulnerable to the messy parts of the modern web: blocked scripts, delayed consent banners, single-page app route changes, failed requests, payment redirects, and cookie restrictions.
TikTok Events API is the server-side companion. Your backend, tag server, or TrackLayer destination sends events directly to TikTok through the Business API. That server event can include order truth, product truth, subscription state, lead quality, normalized hashed identifiers, and consent state captured when the user acted. It is usually more durable than a browser request and easier to monitor like infrastructure. It also has a stricter contract: the server must receive the right browser identifiers, generate or reuse the right event_id, respect consent, and avoid inventing context it never observed.
The strongest 2026 setup uses both. Pixel gives TikTok fast browser evidence, while Events API gives TikTok a verified server-side copy of important events. TikTok then deduplicates the matching browser and server events, keeps one conversion, and uses the combined signals for reporting and optimization. If you run only Pixel, you lose backend durability. If you run only Events API, you lose direct browser context. Running both with a deliberate event contract gives the platform the best chance to understand the conversion without double counting it.
Prerequisites
Step-by-step setup
Build the integration in layers. Prove the endpoint first, then add browser identifiers, then add hashed match keys, then add value and consent. That order keeps debugging concrete because every failed request has a small surface area.
Confirm Pixel ownership and event taxonomy
Start in TikTok Events Manager and verify that the Pixel belongs to the advertiser account you will optimize campaigns from. Align event names before writing server code: ViewContent, AddToCart, InitiateCheckout, CompletePayment, SubmitForm, Subscribe, and Search should mean the same thing in Pixel, Events API, analytics, and your backend logs. TikTok accepts custom names in some workflows, but standard web events are easier to debug and optimize.
POST https://business-api.tiktok.com/open_api/v1.3/event/track/
Access-Token: TIKTOK_ACCESS_TOKEN
Content-Type: application/json
{
"event_source": "web",
"event_source_id": "PIXEL_ID",
"data": []
}Capture browser identifiers before checkout changes context
The browser still sees signals your server may never see later: ttclid from the ad click, _ttp from TikTok's first-party cookie, the user agent, current consent state, and the event_id used by the Pixel call. Capture these at the edge of the session and attach them to the cart, checkout, lead, or order record before redirects, payment pages, or app handoffs can drop them.
{
"event_source": "web",
"event_source_id": "PIXEL_ID",
"data": [
{
"event": "AddToCart",
"event_id": "cart_10492_add_1",
"event_time": 1776943226,
"user": {
"ttclid": "E.C.P.CvQBA...",
"ttp": "2.x9Jb3x...",
"ip": "203.0.113.42",
"user_agent": "Mozilla/5.0..."
}
}
]
}Normalize and hash deterministic identifiers
TikTok can match events better when it receives first-party identifiers collected with the right consent basis. Normalize before hashing: lowercase and trim email, convert phone to a consistent international format, and use a stable external_id such as customer ID or lead ID. Hash email, phone_number, and external_id with SHA-256 unless your tracking layer performs that transformation for you.
{
"event_source": "web",
"event_source_id": "PIXEL_ID",
"data": [
{
"event": "CompletePayment",
"event_id": "ord_10492_payment",
"event_time": 1776943380,
"user": {
"email": "sha256_lowercase_email",
"phone_number": "sha256_e164_phone",
"external_id": "sha256_customer_id",
"ttclid": "E.C.P.CvQBA...",
"ttp": "2.x9Jb3x...",
"ip": "203.0.113.42",
"user_agent": "Mozilla/5.0..."
}
}
]
}Send commercial properties with purchase and cart events
Value-based optimization needs clean revenue fields. Send value as a number, currency as an ISO 4217 code, and contents when product-level attribution or catalog matching matters. Keep tax, shipping, discount, and refund rules consistent with the conversion value you use in campaign reporting. A value field that differs from your backend order total will create finance and media reporting disputes later.
{
"event_source": "web",
"event_source_id": "PIXEL_ID",
"data": [
{
"event": "CompletePayment",
"event_id": "ord_10492_payment",
"event_time": 1776943380,
"user": {
"email": "sha256_lowercase_email",
"external_id": "sha256_customer_id",
"ttp": "2.x9Jb3x...",
"ip": "203.0.113.42",
"user_agent": "Mozilla/5.0..."
},
"properties": {
"value": 129.95,
"currency": "EUR",
"contents": [
{ "content_id": "SKU-481", "quantity": 1, "price": 129.95 }
]
}
}
]
}Attach consent signals and suppress ineligible identifiers
Forward consent state explicitly instead of assuming the platform can infer it from missing fields. TikTok's ad_personalization and ad_user_data signals should reflect the CMP state at the time the event was collected. When ad_user_data is denied in a governed region, remove personal identifiers from the user object. When ad_personalization is denied, send the denial and keep the event governed by your regional policy.
{
"event_source": "web",
"event_source_id": "PIXEL_ID",
"data": [
{
"event": "SubmitForm",
"event_id": "lead_77821_submit",
"event_time": 1776943445,
"user": {
"ttclid": "E.C.P.CvQBA...",
"ttp": "2.x9Jb3x...",
"ip": "203.0.113.42",
"user_agent": "Mozilla/5.0..."
},
"properties": {
"ad_user_data": "DENIED",
"ad_personalization": "DENIED"
}
}
]
}Batch, retry, and log every API response
Events API should behave like payment or email infrastructure: small batches, idempotent retry rules, structured request logs, and alerting on rejected events. Store the event_id, Pixel ID, consent state, match keys present, response code, and TikTok request ID. That makes it possible to fix payload quality without replaying duplicate purchases or guessing which system generated the bad event.
{
"event_source": "web",
"event_source_id": "PIXEL_ID",
"data": [
{
"event": "CompletePayment",
"event_id": "ord_10492_payment",
"event_time": 1776943380,
"user": {
"email": "sha256_lowercase_email",
"phone_number": "sha256_e164_phone",
"external_id": "sha256_customer_id",
"ttclid": "E.C.P.CvQBA...",
"ttp": "2.x9Jb3x...",
"ip": "203.0.113.42",
"user_agent": "Mozilla/5.0..."
},
"properties": {
"value": 129.95,
"currency": "EUR"
}
}
]
}Required fields
TikTok may accept events with fewer fields, but accepted does not mean useful. The production checklist below is built for reliable attribution, deduplication, match quality, and diagnostics.
| Field | Required | Purpose | Example |
|---|---|---|---|
| event_source | Yes | Identifies the origin channel for the event. | web |
| event_source_id | Yes | Routes the event to the correct TikTok Pixel. | C9ABC1234567890 |
| data[].event | Yes | Names the conversion or behavior TikTok should process. | CompletePayment |
| event_time | Yes | Unix timestamp in seconds from the actual event moment. | 1776943380 |
| user.email | Recommended | SHA-256 hashed email for deterministic matching. | sha256(customer@example.com) |
| phone_number | Recommended | SHA-256 hashed phone number after consistent normalization. | sha256(+491701234567) |
| external_id | Recommended | SHA-256 hashed stable customer, lead, or account identifier. | sha256(cust_34982) |
| ttclid | Recommended | TikTok click identifier captured from paid traffic landing URLs. | E.C.P.CvQBA... |
| ttp | Recommended | TikTok browser cookie value used to connect server and web context. | 2.x9Jb3x... |
| ip | Recommended | Client IP address from the user request, not the server IP. | 203.0.113.42 |
| user_agent | Recommended | Browser user agent paired with the event context. | Mozilla/5.0... |
| properties.value + currency | For value events | Revenue and ISO currency used for optimization and reporting. | 129.95 + EUR |
Dedup with Pixel
Deduplication lets TikTok receive a browser event and a server event for the same action without counting two conversions. The convention is simple: generate one event_id for the user action, pass it into the Pixel event, and reuse the exact same value in the Events API payload. Use a readable convention that encodes the business object and action without leaking personal data, such as ord_10492_complete_payment or lead_77821_submit.
const eventId = `ord_${order.id}_complete_payment`;
ttq.track("CompletePayment", {
value: 129.95,
currency: "EUR",
contents: [{ content_id: "SKU-481", quantity: 1 }],
}, {
event_id: eventId,
});
await fetch("/api/tracklayer/tiktok-events-api", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
event_source: "web",
event_source_id: process.env.TIKTOK_PIXEL_ID,
data: [
{
event: "CompletePayment",
event_id: eventId,
event_time: Math.floor(order.paidAt.getTime() / 1000),
user: {
email: sha256(normalizeEmail(order.customer.email)),
phone_number: sha256(normalizePhone(order.customer.phone)),
external_id: sha256(order.customer.id),
ttclid: order.session.ttclid,
ttp: order.session.ttp,
ip: order.session.ip,
user_agent: order.session.userAgent
},
properties: {
value: order.total,
currency: order.currency
}
}
]
})
});TikTok deduplicates matching browser and server events on event_id when it can also associate the server event with the user through email OR phone OR external_id. In practice, send the shared event_id plus as many eligible match keys as consent allows. Do not create a new server-only event_id for the same purchase, and do not reuse one purchase event_id for retries that describe a different action.
Consent signals
TikTok Events API must follow the same consent decision as the browser tag. The important advertising signals are ad_user_data and ad_personalization. ad_user_data describes whether user data may be sent for advertising purposes. ad_personalization describes whether the event may be used for personalized advertising. Keep these as explicit fields in your event envelope, then map them into the TikTok payload or destination policy at dispatch time.
{
"event": "CompletePayment",
"event_id": "ord_10492_complete_payment",
"properties": {
"value": 129.95,
"currency": "EUR",
"ad_user_data": "GRANTED",
"ad_personalization": "DENIED"
}
}GDPR handling should be deterministic. Collect consent before tags and server events fire, attach that state to the event, store the region and CMP version for auditability, and evaluate the TikTok destination before sending identifiers. If ad_user_data is denied, suppress email, phone_number, and external_id. If ad_personalization is denied, preserve the denial instead of assuming TikTok can infer it from missing identifiers. Your backend can still retain the order for fulfillment and first-party analytics under the appropriate legal basis; the advertising export is the governed action.
Testing with Test Events
Test Events should prove the whole path, not just whether the endpoint returns success. Use a real browser session, a real test order, and the same consent banner behavior production users see.
Open Test Events for the production Pixel
Use the Pixel that active campaigns optimize against. Copy the test code or enable the test channel, then send only controlled browser and server traffic until the setup is clean.
Trigger the full browser journey
Visit a landing page with ttclid, browse a product, add to cart, start checkout, and complete a test order. This proves that ttclid, ttp, event_id, consent, and value fields survive the journey.
Compare Pixel and Events API pairs
For deduplicated events, confirm that the browser and server versions share event name and event_id. The server event should include at least one strong match key plus IP and user agent.
Fix diagnostics before removing test mode
Do not promote while TikTok shows missing parameter, invalid token, stale timestamp, duplicate event, or low match quality warnings. Run another ten-minute test window after every fix.
EMQ optimization
Event Match Quality is a diagnostic for how well TikTok can associate your server event with a person or ad interaction. It is not a guaranteed revenue lift, but weak EMQ usually means the algorithm is receiving less conversion evidence than it could. Prioritize the levers below in order.
Hashed email from checkout or login
The strongest common deterministic match key when normalized and collected with valid consent.
Hashed phone number
High value for commerce and lead flows, especially where customers provide mobile numbers for delivery or callbacks.
Stable external_id
Connects repeat customers across browser resets, app handoffs, and future server-only lifecycle events.
ttclid and ttp persistence
Preserves paid-click identity and browser context through landing pages, checkout redirects, and delayed order creation.
IP address plus user agent freshness
Strengthens anonymous and upper-funnel events when captured from the user's request and sent with fresh timestamps.
Troubleshooting
Log raw TikTok responses with enough context to reconstruct the failed event: event_id, Pixel ID, advertiser account, consent state, fields present, timestamp, retry count, and request ID. Without that, every error looks like a platform issue even when the payload is the real problem.
Bad signature or malformed request
Check that the request body is valid JSON, headers are correct, and any signing logic or proxy transformation is not changing the payload after signature calculation.
Token expired or invalid
Regenerate the TikTok Access Token, confirm it belongs to the advertiser that owns the Pixel, and update the encrypted server secret.
Missing permission for event source
Confirm the app, Business Center user, advertiser account, and Pixel asset are connected with Events API access.
Required field missing
Validate event_source, event_source_id, data[].event, event_time, user context, and purchase properties before dispatch.
Invalid parameter format
Check timestamp seconds, ISO currency, numeric value, hashed identifier length, phone normalization, and event name casing.
Duplicate or conflicting event
Use one event_id per user action, reuse it across Pixel and Events API, and prevent multiple backend jobs from sending the same purchase.
FAQ
Can TikTok Events API replace the Pixel?
For most web advertisers, no. The best setup runs both. Pixel captures browser context, click IDs, and fast behavioral events; Events API preserves the conversion signal from the server and enriches it with first-party identifiers.
What event should I use for purchases?
Use CompletePayment for completed ecommerce purchases unless your TikTok account or vertical has a different standard event mapping. Keep the same event name in Pixel and Events API for deduplication.
Do I need to hash ttclid or ttp?
No. Hash personal identifiers such as email, phone_number, and external_id. Send ttclid, ttp, IP address, and user agent as raw context values because TikTok expects those fields in their native form.
How long does EMQ take to improve?
Field warnings can clear quickly after accepted events arrive, but stable Event Match Quality should be judged over at least 24 to 48 hours of normal traffic. Low-volume stores need longer.
Should I send events when consent is denied?
That depends on your legal basis, region policy, platform settings, and event purpose. The practical rule is to attach consent state at collection time, suppress personal identifiers when ad_user_data is denied, and avoid personalization when ad_personalization is denied.
Can I replay missed events?
Only replay events that remain inside TikTok's accepted time window and have stable event_id values. Replaying without idempotency can create duplicates, polluted diagnostics, and campaign learning noise.
Next reads
Build Meta CAPI with access tokens, event_id deduplication, consent forwarding, and EMQ checks.
Send consent-aware first-party conversion signals and click IDs into Google Ads server-side.
Move server-side GTM workflows into a managed conversion pipeline with cleaner diagnostics.