Deduplication Techniques for Meta Pixel + CAPI in osCommerce

Standard

Goal: Prevent duplicate Purchase events in Facebook Ads Manager when both browser-side Pixel and server-side CAPI fire for the same user interaction.


🎯 Why Deduplication?

Without deduplication, Facebook may double count conversions, inflating performance metrics and ruining ad optimization.

Meta’s Deduplication Rule:

To deduplicate, both Pixel and CAPI events must:

  • Have the same event name (e.g., Purchase)
  • Share a common event_id

βœ… Prerequisites

Tool/Asset Purpose
Facebook Pixel ID For browser & server tracking
Facebook CAPI Access Token Server-side events
GTM Web Container Client-side (Pixel) events
GTM Server Container Server-side (CAPI) events
Access to osCommerce For injecting dataLayer and PHP code

πŸ”§ Implementation Plan

  1. Inject event_id into osCommerce
  2. Push purchase data into dataLayer
  3. Fire Pixel tag with event_id
  4. Forward same event (with event_id) to sGTM
  5. Post to Meta CAPI with same event_id
  6. Validate and test for deduplication

πŸ›  Step-by-Step Implementation


πŸ”Ή 1. Inject event_id and Purchase Data in checkout_success.php

File Path: /checkout_success.php

<?php
$order_query = tep_db_query("SELECT orders_id, order_total, customers_email_address FROM " . TABLE_ORDERS . " WHERE customers_id = '" . (int)$customer_id . "' ORDER BY orders_id DESC LIMIT 1");
$order = tep_db_fetch_array($order_query);
$order_id = $order['orders_id'];
$order_total = $order['order_total'];
$customer_email = $order['customers_email_address'];

// Generate a UUIDv4-style event ID
$event_id = bin2hex(random_bytes(16));
?>
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  event: 'purchase',
  transaction_id: '<?= $order_id ?>',
  value: <?= $order_total ?>,
  currency: 'USD',
  email: '<?= $customer_email ?>',
  event_id: '<?= $event_id ?>'
});
</script>

πŸ”Ή 2. GTM Web Container – Facebook Pixel Tag

a. Trigger:

  • Custom Event = purchase

b. Tag: Custom HTML Tag

<script>
fbq('track', 'Purchase', {
  value: {{DLV - value}},
  currency: '{{DLV - currency}}',
  eventID: '{{DLV - event_id}}'
});
</script>

Enable:

  • Trigger: Custom Event = purchase

πŸ”Ή 3. GTM Web β†’ Forward Event to sGTM

a. Tag: HTTP Request Tag

  • URL: https://<your-sgtm-domain>/collect
  • Method: POST
  • Content-Type: application/json

Body Template:

{
  "event_name": "Purchase",
  "event_id": "{{DLV - event_id}}",
  "transaction_id": "{{DLV - transaction_id}}",
  "value": {{DLV - value}},
  "currency": "{{DLV - currency}}",
  "email": "{{DLV - email}}",
  "user_agent": "{{User-Agent}}",
  "ip_override": "{{Client IP}}"
}

πŸ”Ή 4. GTM Server-Side Tag: Facebook CAPI with Deduplication

a. Variables:

Create variables for each field:

  • event_name
  • event_id
  • value
  • currency
  • email
  • transaction_id
  • user_agent
  • ip_override

b. Facebook CAPI Tag Code in sGTM

const sendHttpRequest = require('sendHttpRequest');
const log = require('logToConsole');
const JSON = require('JSON');

// Facebook credentials
const access_token = 'YOUR_FACEBOOK_ACCESS_TOKEN';
const pixel_id = 'YOUR_PIXEL_ID';

// Event data
const event_name = data.event_name;
const event_time = Math.floor(Date.now() / 1000);
const event_id = data.event_id;

const payload = {
  data: [{
    event_name: event_name,
    event_time: event_time,
    event_id: event_id,
    action_source: 'website',
    user_data: {
      em: [sha256(data.email.trim().toLowerCase())],
      client_ip_address: data.ip_override,
      client_user_agent: data.user_agent
    },
    custom_data: {
      currency: data.currency,
      value: data.value,
      order_id: data.transaction_id
    }
  }]
};

sendHttpRequest(
  `https://graph.facebook.com/v18.0/${pixel_id}/events?access_token=${access_token}`,
  {
    method: 'POST',
    headers: {'Content-Type': 'application/json'}
  },
  JSON.stringify(payload)
);

log('Sent deduplicated event to Meta CAPI: ' + event_name);

πŸ”Ή 5. Add SHA256 Email Hash Function

In your template or custom variable:

function sha256(str) {
return Utilities.computeDigest(
Utilities.DigestAlgorithm.SHA_256,
str,
Utilities.Charset.UTF_8
).map(b => ('0' + (b & 0xFF).toString(16)).slice(-2)).join('');
}

πŸ”Ή 6. Validate Deduplication

  1. Use Meta Events Manager > Test Events
  2. Use Meta Pixel Helper (Chrome Extension)
  3. Confirm both events arrive with same event_id
  4. Only one event should be attributed in Ads Manager

⚠️ Debugging Tips

Issue Fix
Two purchases shown in Ads Manager Ensure both client & server send the same event_id
Server event not showing Confirm CAPI call succeeds with HTTP 200
Missing parameters Log payload and inspect in sGTM preview

πŸ” Privacy Best Practices

  • Always hash email before sending to Meta
  • Use client_ip and user_agent from headers
  • Respect user consent before firing CAPI or Pixel

🧠 Summary

Step Action
1 Inject purchase data + event_id in osCommerce
2 Fire Pixel with event_id from GTM Web
3 Forward same data to sGTM
4 Post deduplicated event to Meta CAPI
5 Test in Meta’s Event Manager

βœ… Final Code Recap

  • Purchase dataLayer.push() in PHP βœ…
  • Web GTM Pixel tag with eventID βœ…
  • HTTP request from Web β†’ sGTM βœ…
  • CAPI event with same event_id βœ…
  • Deduplication enabled βœ…

Leave a Reply

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