Deduplicating Events Across GA4, Meta CAPI, and TikTok CAPI for OpenCart

Standard

In a modern OpenCart setup, events like purchase, add_to_cart, and view_item are sent to multiple platforms—GA4, Meta (Facebook) Conversions API, and TikTok Events API. Without proper deduplication, you’ll face:

  • Over-reported conversions
  • Skewed attribution
  • Broken ROAS metrics

🎯 Platforms Covered

Platform Deduplication Key
GA4 Automatic w/ event_id
Meta CAPI event_id (critical)
TikTok CAPI event_id (optional but preferred)


🧰 Prerequisites

  • OpenCart v3.x or v4.x
  • Web GTM + Server GTM (for Meta/TikTok CAPI)
  • GA4 Configured via GTM
  • Meta Pixel + CAPI
  • TikTok Pixel + Events API setup
  • Consent Management (optional)


📦 Step 1: Generate & Push a UUID for Deduplication

In your OpenCart success.twig (on purchase confirmation):

Add This Script to Push event_id:

<script>
(function() {
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}

const eventID = uuidv4();
window.dataLayer = window.dataLayer || [];

dataLayer.push({
event: 'purchase',
event_id: eventID,
transaction_id: '{{ order_id }}',
value: {{ total }},
currency: '{{ currency }}',
items: [/* product loop data here */]
});

// Store event ID in a cookie or localStorage for server use
localStorage.setItem('event_id_purchase', eventID);
})();
</script>

event_id is generated once and used across GA4, Meta Pixel, and TikTok tracking layers.


🧪 Step 2: GA4 Tag with event_id for Purchase

In GTM:

  • Event: purchase
  • Add custom parameter:
    • Name: event_id
    • Value: {{DLV - event_id}}
      (Create a Data Layer Variable)

GA4 automatically supports event_id deduplication.


🔗 Step 3: Meta Pixel + Meta CAPI with Deduplication

A. Meta Pixel Tag (Client-side)

  • Event: Purchase
  • Parameter:
    • eventID: {{DLV - event_id}}

Make sure you are explicitly sending eventID to Pixel.

B. Meta CAPI (Server-side GTM)

Use a GA4 → Server → Meta CAPI flow.

  • Create Meta CAPI tag in Server GTM
  • In the request template:{ "event_name": "Purchase", "event_time": {{Timestamp}}, "event_id": {{event_id}}, "user_data": { "em": {{hashed_email}}, "ph": {{hashed_phone}} }, "custom_data": { "value": {{value}}, "currency": "{{currency}}" } }
  • Retrieve event_id from client via event_id_purchase in cookies or HTTP header.

⚠️ Must match exact value from the client for deduplication to work.


🎯 Step 4: TikTok CAPI Deduplication

TikTok doesn’t require event_id strictly, but recommends it for de-duping against pixel events.

A. TikTok Pixel (Client-Side)

  • Fire Purchase event
  • Pass event_id: {{DLV - event_id}} into advanced matching

B. TikTok Events API (Server-Side)

In Server GTM or middleware, include event_id:

{
"event": "Purchase",
"timestamp": "{{Timestamp}}",
"event_id": "{{event_id}}",
"properties": {
"pixel_code": "YOUR_PIXEL_ID",
"user": {
"email": "{{hashed_email}}"
},
"contents": [...],
"currency": "USD",
"value": 200
}
}

Use a lookup variable or cookie to extract event_id on the server.


🧰 Step 5: Server-Side Retrieval of event_id

Option A: Via Client Cookie → Request Header

Client JS:

document.cookie = "event_id_purchase=" + eventID + "; path=/";

In Server GTM:

  • Use {{Cookie - event_id_purchase}}

Option B: Via x-event-id Header

Send event_id using a custom request header in fetch/XHR if your OpenCart has custom integrations.


📊 Step 6: Reporting Use Cases

Report Type Platform Metric Example
Deduped Purchase Events Meta Ads Events matched = 100%, Deduplicated = 50%
Conversion Matching TikTok Ads event_id match status in TikTok Manager
GA4 Attribution GA4 Clean funnel tracking by event ID


🔐 Consent Integration (Optional)

Wrap deduplication script in consent check:

if (window.Cookiebot && Cookiebot.consents.given.analytics) {
// execute uuid generation + dataLayer.push
}

Or set server-side triggers to only fire with consent=true.


🧠 Pro Tips

  • Always log event_id with order data in your backend DB for reconciliation
  • Use the same timestamp granularity (epoch seconds) across systems
  • Avoid multiple event_id generations for the same action


Leave a Reply

Your email address will not be published. Required fields are marked *