The official plugin blocks PHP for 300ms and crashes checkouts. Ad blockers kill your pixel data. This guide walks through the full hybrid architecture — browser pixel, server-side Events API, GTM container, deduplication logic, and EMQ validation.
The TikTok Events API — also called TikTok CAPI — is a direct server-to-server connection between your backend and TikTok's ad platform. Instead of firing from a visitor's browser, it fires from your server. TikTok receives the data regardless of what happens in the browser.
That matters because browsers are unreliable for conversion tracking. Ad blockers, Safari's Intelligent Tracking Prevention (ITP), iOS 14.5+ privacy restrictions, and users closing tabs early all cause pixel data to disappear. When your Purchase signals drop, TikTok's algorithm optimizes on incomplete data — ROAS looks wrong, retargeting audiences shrink, and CPA climbs.
The Events API moves critical conversion signals off the browser entirely, so they arrive reliably regardless of the visitor's device or privacy settings.
Intelligent Tracking Prevention is Apple's system for blocking third-party cookies and cross-site tracking. It runs on all Safari browsers — including Chrome on iOS. Server-side tracking bypasses these restrictions because data moves server-to-server, not through the client browser.
The Events API does not replace the TikTok Pixel. It complements it. Running both simultaneously — the hybrid model — is the official recommendation for complete signal coverage.
The pixel captures real-time session behavior: page views, add-to-cart clicks, checkout starts. The API guarantees transaction data: confirmed purchases with full order details and hashed customer identity. When both fire for the same event, TikTok's deduplication logic merges them into one accurate conversion record.
event_id → TikTok merges them into 1 conversion, not 2.TikTok uses a fixed set of standard event names. You must map WooCommerce actions to these exact names. Using the wrong name means data goes nowhere useful for campaign optimization.
Older documentation and some plugins still reference CompletePayment and PlaceAnOrder. These are being deprecated. Use Purchase for all new implementations — it is the forward-compatible API v2.0 standard.
| WooCommerce Action | TikTok Event | Required Parameters | Purpose |
|---|---|---|---|
| Product page loads | ViewContent | content_ids, content_type, value, currency | Dynamic retargeting catalog |
| Item added to cart | AddToCart | content_ids, content_type, quantity, value, currency | Cart abandonment sequences |
| Checkout page loads | InitiateCheckout | content_ids, content_type, value, currency | High-intent prospect pool |
| Payment confirmed | Purchase | content_ids, content_type, value, currency, quantity, order_id | ROAS, algorithm training, suppression |
The Purchase payload is the most important. Below is the required JSON structure for a modern server-side API call:
{ "event_source": "web", "event_source_id": "PIXEL_ID_HERE", "data": [{ "event_name": "Purchase", "event_time": 1700000000, // UNIX timestamp "event_id": "wc_order_891", // MUST match browser pixel exactly "user": { "email": "SHA256_HASHED_EMAIL", // lowercase → trim → hash "phone": "SHA256_HASHED_PHONE", "ttclid": "TIKTOK_CLICK_ID", // strongest match key "ip": "203.0.113.1", "user_agent": "Mozilla/5.0..." }, "properties": { "currency": "USD", "value": 89.99, "content_type": "product", "content_ids": ["SKU-123"], "quantity": 1 } }] }Two rules govern this payload. The event_id must exactly match what the browser pixel sent for the same order. The email and phone must be lowercased, whitespace-trimmed, then SHA-256 hashed before they leave your server.
Three main plugin options exist for connecting TikTok Events API to WooCommerce without a full custom build. Each has documented tradeoffs worth understanding before going live.
The official TikTok for WooCommerce plugin has a well-documented history of generating duplicate WooCommerce orders. This creates real accounting errors and corrupts data going to TikTok's algorithm. Check the WordPress.org support forum for your version before activating on a live store.
Not sure which setup fits your store? A proper audit looks at your dataLayer, caching config, and checkout flow before recommending a plugin or custom build.
View Tracking Services →For high-volume WooCommerce stores, the most reliable architecture is Google Tag Manager Server-Side (GTM SS). It separates tracking logic from your WordPress server entirely. WooCommerce pushes data to a dataLayer in the browser. A dedicated server container handles all outbound API calls.
Three core advantages over plugin-based setups: it does not block PHP execution, it gives you precise control over every parameter sent to TikTok, and it handles multiple ad platforms from one container — no stacking plugins for each network.
Use Stape.io (fixed monthly pricing, visual payload logs) or Google Cloud Run (pay-per-request, infinite scale). Map it to a custom subdomain like metrics.yourstore.com — required for first-party cookie writing.
Find it in the GTM Community Template Gallery. Add your Pixel ID and the Access Token from TikTok Ads Manager → Events → Manage → Settings → Generate Access Token.
GA4 and TikTok use different field names. Create GTM variables to transform them on every event: item_id → content_id, price → price, quantity → quantity.
SHA-256 hash email and phone using a custom JavaScript variable in the web container — before data leaves the browser. Raw PII should never reach your tagging server or appear in access logs.
Generate the event_id from the WooCommerce order number and pass it in both the browser pixel and the server payload. This is the only mechanism that enables deduplication.
Stape.io has a fixed monthly cost and a visual interface for inspecting historical payloads without writing queries. GCP Cloud Run is cheaper at very high volume but requires SQL to debug logs. For most WooCommerce stores, Stape.io is faster to set up and easier to troubleshoot. Full comparison: Stape vs Google Cloud for GTM →
The custom subdomain is not optional. When your GTM server container runs on metrics.yourstore.com, the TikTok ttp cookie is written as a first-party cookie — Safari and iOS cannot block it. This is how server-side tracking restores the identity data that ITP strips in client-side setups.
When both the browser pixel and the Events API fire for the same purchase, TikTok records only one conversion by matching two fields: event_name and event_id. Both must be identical strings in both payloads.
| Source A | Source B | Window | Behavior |
|---|---|---|---|
| Browser Pixel | Browser Pixel | 48 hours | Merges duplicate pixel fires in the same session |
| Server API | Server API | 48 hours | Catches duplicate server retries or webhook loops |
| Browser Pixel | Server API | 5 min – 48 hrs | The hybrid window. Events within 5 min merge instantly. |
"891" (string). Server sends 891 (integer). TikTok treats them as different values.order-891 vs order_891 — one character difference breaks the match.A broken dedup setup causes conversion volume to double in Ads Manager. ROAS looks artificially high. CPA looks low. The algorithm trains on false data and performance degrades over time.
Running into this on Meta too? The same event_id matching pattern applies to Facebook's Conversions API. Our fix guide covers both platforms.
Two distinct failure types require different approaches. Identify which one you have before touching any code.
| Error Type | What It Means | HTTP Response | Where to Debug |
|---|---|---|---|
| Not Received | The API request never reached TikTok. Malformed JSON, invalid access token, or wrong data type (string passed where float expected). | 4xx Error | Server logs, GTM Preview, TikTok Test Events tool |
| Not Matched | TikTok received the event but cannot link it to a user or ad click. PII missing, incorrectly hashed, or ttclid lost in transit. | 200 OK | Events Manager → EMQ score → match key breakdown |
content_ids, value, and event_id live on the page. Cannot see server traffic.test_event_code to your server payload to route it into a sandbox. Inspect the exact JSON structure without affecting live reporting or algorithm training.The three most common causes:
The fix for all three: fire the Purchase event from the server using the woocommerce_payment_complete hook — which triggers on order status changing from "pending" to "processing" — rather than relying on a frontend page load.
$_POST or the WooCommerce checkout session before hashingttclid being stripped by a redirect or URL cleaner pluginGuest users have no WordPress user ID. Your server cannot look them up during the purchase event. Instead, use session-based identity storage: when a visitor arrives from a TikTok ad, capture the ttclid and ttp cookie values immediately and store them in a session variable. When the guest submits checkout, those values are available server-side alongside billing email and phone.
If the ttclid gets stripped during checkout — by a redirect, URL cleaner plugin, or cross-domain navigation — your payload loses its strongest match key. EMQ drops sharply and TikTok cannot attribute the conversion back to the ad click.
Every Purchase payload must include the correct ISO 4217 currency code matching the transmitted amount. If a customer pays 10,000 JPY and your payload sends that number with "currency": "USD", TikTok's ROAS calculation is off by roughly 140x. Either send the display currency with the exact checkout amount and let TikTok convert internally, or convert to your base reporting currency before transmission. Either works — the critical rule is that currency must always match value.
Renewal payments run through cron jobs with no active browser session. The pixel cannot fire. Hook the Events API directly into renewal execution using the woocommerce_scheduled_subscription_payment_{gateway_id} hook. This fires a new Purchase event the moment the payment clears — ensuring recurring revenue gets attributed back to the original TikTok acquisition campaign.
A second Purchase event with the same event_id as the original order gets discarded as a duplicate. You lose the upsell revenue data entirely. The fix: append a unique suffix to the event_id for each upsell.
// Initial purchase — normal event_id "event_id": "wc_order_891"// Order bump — suffix bypasses dedup filter "event_id": "wc_order_891_bump_1"// Second upsell "event_id": "wc_order_891_bump_2"Server-side tracking does not bypass consent requirements. If a user declines advertising cookies via your Consent Management Platform, the Events API must be suppressed or fully anonymized — no email, no phone, no ttclid, no ttp cookie. Your CMP's consent state must gate both the browser pixel and the server-side execution independently.
A properly working hybrid setup shows a specific fingerprint in TikTok Events Manager. Here is what to look for.
EMQ is scored 0–10. It measures how confidently TikTok can link a server event to a real user profile and ad click.
Purchase events should consistently score 8–10. You have full billing data at checkout — if your Purchase EMQ is below 8, something is broken in your PII extraction or hashing logic, not a data volume issue.
ViewContent and AddToCart will naturally score 3–6. No PII has been submitted yet. This is expected behavior and not a problem to fix.
Do not reconcile TikTok data in real time. The processing engine can take up to 6 hours to show an event in Events Manager, and the deduplication window takes up to 48 hours to finalize. Always use a 48-hour trailing window when comparing WooCommerce order counts to TikTok conversion reports.
Need this implemented correctly? We handle the full build — GTM server container, dataLayer mapping, deduplication logic, PII hashing, and EMQ validation — as part of our tracking integrity service.
Get in Touch →