TikTok Events API Deduplication: Fix Double-Counted Events

Quick fix: Send the same event_id, the same event name and the same pixel code from both the TikTok Pixel and the Events API for each conversion. On the pixel, event_id goes in the third argument of ttq.track(), not inside the event properties. For purchases, the order ID makes a good shared ID.

Sending conversions from both the browser pixel and your server is the recommended setup on TikTok. The server copy fills gaps when the browser event is blocked. But if TikTok can't tell that the two copies describe the same conversion, it counts both. Your reported purchases go up, cost per purchase looks better than it is, and the campaign optimizes on bad data.

This guide explains how TikTok matches the two copies and the mistakes that most often break it. It also shows how to check that it works.

How TikTok decides two events are duplicates

TikTok's deduplication relies on three values that must be identical in the pixel event and the server event:

  • Pixel code. On the pixel, this is the ID in ttq.load(). In the Events API, it's the event_source_id field.
  • Event name. For example Purchase in both.
  • Event ID. A string you choose that is unique to that one conversion.

TikTok's help center says duplicates arriving within 5 minutes of each other are merged, and fields missing from the first event can be filled from the second. Duplicates arriving later, within 48 hours of the first event, are dropped. TikTok keeps the first event it receives for reporting. Read TikTok's article on event deduplication for the full rules.

You only need deduplication when the same event goes through both channels. If you send AddToCart only from the pixel and Purchase only from the server, there is nothing to deduplicate.

Step 1: Check that event_id is in the right place on the pixel

This is the most common mistake. The pixel's ttq.track() call takes three arguments: the event name, the event properties and an options object. event_id belongs in the third one:

ttq.track('Purchase', {
  value: 84.50,
  currency: 'USD',
  content_type: 'product',
  content_ids: ['SKU-123']
}, {
  event_id: 'order_100457'
});

If you put event_id inside the properties object, TikTok reads it as an ordinary property, not as a deduplication key. The pixel copy then arrives without an ID and can't be matched to the server copy.

If you use a tag manager template or a platform app, check its settings for an "event ID" field. Then confirm in the browser that the request actually carries it.

Step 2: Use the same ID on both sides

The ID has to be decided once and shared. It can't be generated separately by the browser and the server. Two independent random numbers never match.

Good sources for a shared ID:

  • Purchases: the order number or transaction ID. Your thank-you page and your order webhook both know it.
  • Leads and sign-ups: generate an ID (a UUID works) in the browser. Send it with the pixel event and pass it to your server with the form submission so the server event reuses it.
  • Other events: generate the ID once per action and pass it through your data layer to both the pixel tag and the server-side tag.

Never use the same ID for different conversions. If every purchase on your site sends event_id: "purchase", TikTok treats real, separate orders as duplicates and drops them.

Also make sure the value is a real rendered string. A tag that sends a template placeholder like {{order_id}} literally gives every event the same ID.

Step 3: Send the same event name

The pixel and the server must use identical event names. Mismatches often happen during migrations. For example, the pixel still sends CompletePayment while a new server integration sends Purchase.

TikTok renamed CompletePayment to Purchase and says legacy names are converted on its side. Even so, don't rely on that conversion for deduplication. Use the exact same name in both channels. For new setups, use Purchase. See TikTok's guide to adopting the updated standard events.

Step 4: Send the server event to the same pixel

If your site loads pixel A and your server sends to pixel B, nothing will deduplicate. The two pixels are separate data sources. This happens after agency handovers, when a new pixel is created for the Events API by mistake.

Compare the ID in ttq.load() with the event_source_id your server sends. Use one pixel for both.

Step 5: Build a correct Events API payload

TikTok recommends Events API 2.0, which uses the /event/track/ endpoint for web, app, offline and CRM events. A web purchase looks roughly like this (field names from TikTok's Events API reference; check the current version before you build):

POST https://business-api.tiktok.com/open_api/v1.3/event/track/
Access-Token: YOUR_ACCESS_TOKEN

{
  "event_source": "web",
  "event_source_id": "YOUR_PIXEL_CODE",
  "data": [{
    "event": "Purchase",
    "event_time": 1793088000,
    "event_id": "order_100457",
    "user": {
      "email": "SHA256_OF_LOWERCASE_EMAIL",
      "ttp": "VALUE_OF_THE__ttp_COOKIE",
      "ttclid": "VALUE_FROM_THE_LANDING_URL",
      "ip": "203.0.113.10",
      "user_agent": "Mozilla/5.0 ..."
    },
    "page": { "url": "https://example.com/thank-you" },
    "properties": {
      "currency": "USD",
      "value": 84.50,
      "content_type": "product",
      "contents": [{ "content_id": "SKU-123", "quantity": 1, "price": 84.50 }]
    }
  }]
}

A few points about this payload:

  • ttp is the value of the _ttp cookie that the pixel sets. Forwarding it helps TikTok tie the server event to the same browser.
  • ttclid is the click ID TikTok adds to ad landing page URLs. Save it when the visitor lands so you can send it later.
  • Email, phone and external_id must be SHA-256 hashed before you send them. TikTok also recommends sending both the IP address and the user agent.
  • event_time should be the time the conversion happened, not when your queue processed it.

The full field list is in TikTok's Events API reference.

Step 6: Send server events promptly

TikTok's dedup windows are measured from the first event. If your server batches events and sends them days later, they fall outside the 48-hour window and are counted as new conversions. TikTok's docs recommend sending events in real time. Send each server event as soon as the conversion happens, or at least well within the window.

Step 7: Check for a third copy

Deduplication matches one pixel event to one server event. If your store also has a second browser install (a hand-pasted snippet plus a platform app, for example), you may be sending two pixel events with different IDs plus a server event. Fix the extra browser install first. Our guide to a TikTok Pixel that isn't firing covers how to find duplicate installs.

How to verify deduplication

  1. Check the browser request. Place a test order with the Network tab open. Find the TikTok request for Purchase and confirm it contains your pixel code, the event name and the event_id you expect.
  2. Check the server log. Find the matching Events API request for the same order. The event_id, event name and event_source_id must be identical to the browser's.
  3. Use Test Events. In Events Manager, open your pixel's Test Events tab. Browser events arrive through a test session on your site. Server events arrive when your request includes the test_event_code shown in that tab. Remove the test code when you finish, so real events aren't treated as tests.
  4. Compare counts after launch. Over a few days, compare purchase counts in Events Manager with orders in your store. A large gap upward points to failed deduplication. A gap downward can mean IDs are being reused across different orders.

Before you switch on server events, write down which events go through each channel and where the shared ID comes from. Our pixel tracking launch checklist includes this step. The same approach works on other platforms. Compare it with Meta Pixel and Conversions API deduplication.

FAQ

Do I need deduplication if I only use the Events API?

Not across channels. TikTok also deduplicates repeated events from a single channel with the same event name and event_id within 48 hours. That protects you if your server retries a request.

What should I use as the event_id for page views or add-to-cart?

Any unique string generated once per action, such as a UUID, shared through your data layer with both the pixel and the server tag. Only events you send through both channels need it.

Which copy does TikTok keep?

TikTok records the first event it receives. If the second copy arrives within 5 minutes, fields missing from the first can be filled from the second. Sending complete data in both copies is the safest approach.

Can I check deduplication with a browser extension?

Only the browser half. An extension can show you the pixel's event_id, but it can't see server-to-server requests. Compare the browser value with your server logs and use Test Events for the server side.