TikTok Events API: server-side setup that actually improves match quality
The TikTok Pixel alone loses a growing share of events to ad blockers and in-app browsers. The Events API sends conversions server-side — but match quality lives or dies on identifiers and event dedup. Here is the setup that works.
TikTok's Events API sends conversions from your server to TikTok, the same way Meta's Conversions API does. It is worth setting up for one measurable reason: match quality. A browser-only TikTok Pixel loses events to blockers and in-app browser quirks, and the events that do arrive often carry too little identity to match a user. A server implementation with hashed email, phone, and the TikTok click ID typically matches far better — which is what actually improves optimisation.
How the pieces fit together
TikTok's measurement has two paths, and you want both:
- The Pixel runs in the browser via ttq, sets the _ttp cookie, and captures ttclid — the click ID appended to URLs when someone arrives from a TikTok ad.
- The Events API posts events from your server, carrying whatever identity you attach.
The pixel supplies the identifiers; the server supplies the reliability. Neither is sufficient alone, which is the same architecture Meta uses and for the same reasons.
Step 1: Capture the identifiers in the browser
This step is where most implementations quietly fail, and it happens before any server code exists.
When a visitor lands from a TikTok ad, the URL carries ttclid. It is present on the landing page and gone by the time they check out. So capture it immediately, persist it, and attach it to the order record:
// On landing
const params = new URLSearchParams(window.location.search);
const ttclid = params.get('ttclid');
if (ttclid) {
sessionStorage.setItem('ttclid', ttclid);
}
Do the same for the _ttp cookie, plus the visitor's user agent and IP as seen by your server at order time. Without these, your server events describe an anonymous transaction and match almost nobody.
Step 2: Normalise and hash the customer data
TikTok expects SHA-256 hashes of normalised values. Normalisation is not optional — hash the wrong shape and the hash simply does not match TikTok's:
| Field | Normalise to | Then |
|---|---|---|
| lowercase, trimmed | SHA-256 | |
| Phone | E.164, digits only with country code | SHA-256 |
| External ID | your stable customer ID | SHA-256 |
| ttclid | as received | send raw |
| _ttp | as received | send raw |
| IP / user agent | the visitor's, not your server's | send raw |
That last row is the second most common failure. If your backend sends its own IP and user agent, every event looks like it originated in a data centre.
Step 3: Send the event server-side
Post the event when the thing actually happens — an order written, a lead qualified — rather than when a page renders. Include:
- event — use TikTok's standard names (CompletePayment, AddToCart, CompleteRegistration) rather than inventing your own, or reporting and optimisation will not recognise them.
- event_id — a stable, unique ID shared with the browser event, for deduplication.
- event_time — a Unix timestamp, close to real time.
- user — the hashed identifiers plus ttclid, ttp, IP, and user agent.
- properties — value, currency, contents, order ID.
Step 4: Deduplicate against the pixel
The rule is identical to Meta's: same event name, same event ID, from both browser and server, close together in time.
// Browser
ttq.track('CompletePayment', {
value: 129.00, currency: 'USD'
}, { event_id: 'order_10432_payment' });
// Server — same string
"event_id": "order_10432_payment"
If your TikTok conversion count roughly doubled after enabling the Events API, deduplication is failing. Check the event ID before anything else.
Step 5: Verify with real data
- Events Manager diagnostics. TikTok reports match rates and flags missing parameters. This is your primary feedback loop — treat warnings there as work items, not noise.
- Compare counts. Server events should be somewhat higher than browser events, not double. Double means dedup is broken; equal means the server is only echoing what the browser already delivered.
- Reconcile to your order system. Total conversions should approximate real orders from TikTok traffic, allowing for consent and attribution differences.
- Watch match quality over time. A drop usually means an identifier stopped being captured — a landing-page change that dropped the ttclid capture is the classic cause.
Where to run it
Four options, in rough order of effort:
- Platform integration. Shopify and other major carts have TikTok apps that handle Events API for you. Least control over payload, least effort.
- TikTok's own partner integrations, where available for your stack.
- Server-side GTM. A server container fans the same event out to TikTok alongside Meta, GA4, and Google Ads. Sensible if you are already running one — when it is worth it.
- Direct from your backend. Most accurate and durable, because it fires from the system of record. Requires handling retries and errors properly.
The mistakes that cost the most
- No ttclid capture. The strongest attribution signal, lost because nobody stored it on the landing page.
- Server IP and user agent instead of the visitor's. Match quality collapses.
- Unhashed email or phone. A policy violation and a failed match.
- Custom event names where standard ones exist, breaking optimisation and reporting.
- Server-only implementations that drop the pixel, giving up the cookie and click ID entirely.
FAQ
Do I still need the TikTok Pixel if I use the Events API?
Yes. The pixel sets _ttp and is how you observe ttclid in the first place. The Events API without those identifiers matches poorly.
Will the Events API double-count my conversions?
Not if both sources send the same event name and the same event_id close together in time. Doubled numbers after go-live are a deduplication failure, not expected behaviour.
What is a good TikTok match rate?
Higher is better and the practical target is to keep improving it rather than to hit a specific figure. If it is low, check in order: hashed email present, phone present, ttclid captured, visitor IP and user agent forwarded.
Does the Events API bypass consent requirements?
No. Sending identifiers from your server is the same processing as sending them from the browser. Gate server sends on consent state just as you gate the pixel.
Can I send historical conversions to backfill?
TikTok expects events close to real time; late events lose attribution value and may be rejected. Fix the pipeline forward rather than trying to backfill.
Check whether your TikTok Pixel is even initialising — the free tracking audit checks it alongside GA4, Meta, and Google Ads on any URL.
See where your tracking stands
Run the same 13-check audit referenced in this post against any URL. No signup, results in seconds.