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 ✅

Using Consent-Conditional Tags in GTM for OpenCart’s Multiple Ad Tools

Standard

Managing compliance across multiple advertising tools—like Google Ads, Meta Pixel, TikTok, Pinterest, and LinkedIn—is critical for OpenCart merchants in a privacy-first world. The most effective solution? Leverage Consent-Conditional Tagging using Google Tag Manager (GTM) and Consent Mode v2 to selectively fire tags only when user consent is granted.

🧰 Prerequisites

Requirement Description
OpenCart (v3.x or v4.x) eCommerce platform
Google Tag Manager Web container installed site-wide
CMP (e.g. Cookiebot, OneTrust) Consent platform integrated
Multiple Ad Pixels Google, Meta, TikTok, Pinterest, LinkedIn
Consent Mode v2 Enabled in GTM and supported by CMP


📦 Step 1: Add Consent Initialization Tag in GTM

Before any tags fire, include a Consent Initialization tag:

  1. Tag Type: Consent Initialization – Google tag (gtag.js)
  2. Configuration:

gtag('set', 'default_consent', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied'
});

  1. Trigger: Consent Initialization – All Pages


🌐 Step 2: Integrate CMP into OpenCart (e.g., Cookiebot)

Insert the CMP script inside OpenCart’s catalog/view/theme/YOUR_THEME/template/common/header.twig.

Cookiebot Example:

<script id="Cookiebot"
src="https://consent.cookiebot.com/uc.js"
data-cbid="YOUR_ID"
data-blockingmode="auto"
type="text/javascript"
async></script>

Configure your CMP to support Consent Mode v2 and map categories like marketing, statistics, personalization to Consent Mode signals.


🎯 Step 3: Tag Consent Settings in GTM

For each tag (Google Ads, Meta, TikTok, etc.), configure the Consent Settings.

Example: Google Ads Conversion Tag

  1. Edit the tag in GTM
  2. Scroll to Consent Settings
  3. Turn on: “Require Additional Consent”
  4. Add:

ad_storage
ad_user_data
ad_personalization

Repeat for:

Platform Required Consents
Google Ads ad_storage, ad_user_data, ad_personalization
Meta Pixel ad_storage, ad_user_data
TikTok ad_storage
Pinterest ad_storage
LinkedIn ad_storage


🛠️ Step 4: Custom Consent-Aware Firing with JavaScript (Optional)

You can also manually control Custom HTML tags based on CMP logic.

Example: Meta Pixel Tag (Custom HTML)

<script>
if (window.Cookiebot && Cookiebot.consents.given.marketing) {
fbq('track', 'Purchase', {
value: {{DL - value}},
currency: '{{DL - currency}}'
});
}
</script>

Trigger: Page View or Purchase Page (as needed)

Replace with your CMP’s consent API if not using Cookiebot.


🛒 Step 5: Trigger Consent-Based Custom Events in Data Layer

In success.twig or product.twig, only push custom events if consent is granted:

<script>
if (window.Cookiebot && Cookiebot.consents.given.marketing) {
dataLayer.push({
event: 'purchase',
transaction_id: '{{ order_id }}',
value: {{ order_total }},
currency: '{{ currency }}'
});
}
</script>

This ensures events are not pushed prematurely or without permission.


📊 Step 6: Debug Consent & Tag Behavior

Use the following tools:

Tool Use Case
GTM Preview Check if tags are blocked/fired
Google Tag Assistant Shows consent state on page
GA4 DebugView Validates event and user behavior
Pixel Helpers (Meta, TikTok, Pinterest) Confirm event receipt


🔐 Optional: Server-Side Consent Propagation

If you use Server-Side GTM, pass consent as headers:

eventData.headers = {
'x-consent-ad_storage': 'granted',
'x-consent-ad_user_data': 'denied'
}

Use these headers to conditionally route data to platforms server-side.


🧠 Pro Tips

  • Use GTM Triggers with Consent Conditions:
    • Trigger fires only if "ad_storage" === granted
  • Use Lookup Tables to map:
    • CMP categories → Consent Mode variables
  • Bundle all marketing scripts inside one tag, fired conditionally for performance


✅ Benefits of Consent-Conditional Tagging

Benefit Description
Legal Compliance Meets GDPR, ePrivacy, CCPA standards
Trust Building Enhances user transparency
Smart Attribution Cookieless pings used until consent is granted
Cross-Platform Consistency Standardized behavior for all ad pixels
Easy Tag Maintenance All tag logic lives within GTM


Facebook CAPI Server-Side Integration for osCommerce Purchases

Standard

Use Case:
You’re running Meta (Facebook/Instagram) ads for your osCommerce store and want to:

  • Improve Purchase attribution
  • Send events server-to-server
  • Respect privacy and consent
  • Reduce reliance on client-side pixels

✅ Prerequisites

Tool Purpose
Facebook Business Manager Access to Pixel & CAPI Token
GTM Web Container To send event data from client
GTM Server Container To send Purchase data to Meta
Access to osCommerce For injecting dataLayer code

🚀 Step-by-Step Implementation


🔹 1. Get Your Facebook CAPI Access Token

  1. Go to Facebook Events Manager
  2. Select your Pixel > Settings
  3. Scroll to “Conversions API” > Generate Access Token
  4. Copy and store the token securely

🔹 2. Set Up GTM Server-Side (sGTM)

  1. Create a Server container in GTM
  2. Deploy it via Google Cloud App Engine or Cloud Run
gcloud app deploy
  1. Note your sGTM endpoint (e.g., https://gtm.yourdomain.com)

🔹 3. Add GTM Web Container to osCommerce

Paste the GTM Web snippet into:

  • <head>: /includes/template_top.php
  • <body>: noscript iframe after opening <body>

🔹 4. Inject Purchase Event on checkout_success.php

osCommerce PHP Template Code:

<?php
$order_query = tep_db_query("SELECT orders_id, order_total 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'];
?>
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'purchase',
transaction_id: '<?= $order_id ?>',
value: <?= $order_total ?>,
currency: 'USD',
email: '<?= $customer_email ?>'
});
</script>

🔹 5. Create Web GTM Tag to Send Purchase to sGTM

a. Trigger:

  • Custom Event = purchase

b. Tag: HTTP Request

  • Tag Type: Custom Tag → HTTP Request
  • URL: https://gtm.yourdomain.com/collect

Payload Template:

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

🔹 6. Configure sGTM to Handle Facebook CAPI

a. Create Variables in sGTM:

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

🔹 7. Create a Tag Template or Custom HTML Tag in sGTM

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

const access_token = 'YOUR_FACEBOOK_ACCESS_TOKEN';
const pixel_id = 'YOUR_PIXEL_ID';

const event_id = data.transaction_id || 'txn_' + Math.random().toString(36).substr(2, 10);
const event_name = data.event_name;
const event_time = Math.floor(Date.now() / 1000);

const payload = {
  data: [{
    event_name: event_name,
    event_time: event_time,
    event_id: event_id,
    action_source: 'website',
    user_data: {
      em: [data.email ? 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 FB CAPI event: " + event_name);

Include a sha256 hashing function in template if required.


🔹 8. Hashing Email with SHA-256

In sGTM, add this email hashing function:

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('');
}

Alternatively, hash emails in GTM Web before sending to sGTM using Custom JavaScript Variable.


🔹 9. Enable Debugging in Events Manager

Append this to the CAPI URL temporarily:

&test_event_code=TEST123

Example:

https://graph.facebook.com/v18.0/123456789/events?access_token=xyz&test_event_code=TEST123

See test events appear in Events Manager under “Test Events”.


🔹 10. Deduplicate Events (Optional but Recommended)

Send the same event_id from both client-side and server-side implementations.

  • In your Pixel base code tag:
fbq('track', 'Purchase', {
value: 199.99,
currency: 'USD',
eventID: 'txn_ABC123'
});

Send same event_id in sGTM.


📊 Final Testing Checklist

✅ Facebook Pixel Helper (Chrome Extension)
✅ Meta Events Manager > Test Events
✅ Verify Purchase events show parameters
✅ Confirm no duplication in attribution reports


🔐 Compliance & Privacy

  • Hash all PII (e.g., email) before sending to Meta
  • Respect user consent using Consent Mode or custom consent triggers
  • Avoid sending raw data without opt-in

📌 Summary

Step Action
1 Get FB Access Token
2 Set up GTM Web + sGTM
3 Inject purchase dataLayer in osCommerce
4 Forward data to sGTM using HTTP Tag
5 Process purchase event using FB CAPI
6 Test and validate
7 Optionally deduplicate client & server events

 

Advanced Guide: Installing Facebook Pixel in osCommerce Using GTM

Standard

Facebook Pixel is critical for:

  • Tracking visitor actions (AddToCart, Purchase, etc.)
  • Creating retargeting audiences
  • Measuring conversions from Meta Ads

In this guide, we’ll implement the Facebook Pixel in osCommerce via Google Tag Manager, covering:

  • Pixel base code
  • Dynamic eCommerce events
  • Custom data layer setup
  • Enhanced Purchase tracking
  • Debugging

✅ Prerequisites

Tool Requirement
Facebook Business Manager Pixel ID
GTM Account Web container
Access to osCommerce Edit templates or inject GTM snippet
Admin rights To modify checkout/order confirmation pages

🚀 Step-by-Step Setup


🔹 1. Add GTM to osCommerce

a. Install GTM Snippet

Edit your theme header file (e.g., /includes/header.php or template_top.php) and insert GTM container code right after <head> tag:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->

Also add the noscript iframe version right after <body> tag.


🔹 2. Add Facebook Pixel Base Code in GTM

a. Create a New Tag in GTM

  • Tag Type: Custom HTML
  • Tag Name: FB Pixel – Base Code
  • HTML Code:
<script>
  !function(f,b,e,v,n,t,s)
  {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
  n.callMethod.apply(n,arguments):n.queue.push(arguments)};
  if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
  n.queue=[];t=b.createElement(e);t.async=!0;
  t.src='https://connect.facebook.net/en_US/fbevents.js';
  s=b.getElementsByTagName(e)[0];
  s.parentNode.insertBefore(t,s)}(window, document,'script');
  
  fbq('init', 'YOUR_PIXEL_ID');
  fbq('track', 'PageView');
</script>
<noscript>
  <img height="1" width="1" style="display:none"
       src="https://www.facebook.com/tr?id=YOUR_PIXEL_ID&ev=PageView&noscript=1"/>
</noscript>

Replace 'YOUR_PIXEL_ID' with your actual Pixel ID.

  • Trigger: All Pages

🔹 3. Configure osCommerce Data Layer for eCommerce Events

You’ll need to inject data layer events in osCommerce templates for actions like Add to Cart, Initiate Checkout, and Purchase.


🔹 4. AddToCart Event Setup

a. Modify Product Page Template (product_info.php)

Before the closing </body>, inject:

<?php if (isset($_GET['products_id'])) {
    $product_id = (int)$_GET['products_id'];
    $product_query = tep_db_query("SELECT products_name, products_price FROM " . TABLE_PRODUCTS_DESCRIPTION . " pd, " . TABLE_PRODUCTS . " p WHERE pd.products_id = p.products_id AND pd.language_id = '" . (int)$languages_id . "' AND p.products_id = '" . (int)$product_id . "'");
    $product = tep_db_fetch_array($product_query);
?>
<script>
  window.dataLayer = window.dataLayer || [];
  document.querySelector('form[name="cart_quantity"]').addEventListener('submit', function() {
    dataLayer.push({
      event: 'add_to_cart',
      ecommerce: {
        content_ids: ['<?= $product_id ?>'],
        content_name: '<?= addslashes($product['products_name']) ?>',
        value: <?= $product['products_price'] ?>,
        currency: 'USD'
      }
    });
  });
</script>
<?php } ?>

b. GTM Tag for AddToCart

  • Tag Type: Custom HTML
  • Trigger: Custom Event = add_to_cart
  • HTML:
<script>
  fbq('track', 'AddToCart', {
    content_ids: {{DLV - ecommerce.content_ids}},
    content_name: {{DLV - ecommerce.content_name}},
    value: {{DLV - ecommerce.value}},
    currency: {{DLV - ecommerce.currency}}
  });
</script>

🔹 5. Purchase Event Setup

a. Inject Data Layer on Thank You Page (checkout_success.php)

<?php
$order_query = tep_db_query("SELECT orders_id, order_total 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'];
?>
<script>
  window.dataLayer = window.dataLayer || [];
  dataLayer.push({
    event: 'purchase',
    ecommerce: {
      value: <?= $order_total ?>,
      currency: 'USD',
      transaction_id: '<?= $order_id ?>'
    }
  });
</script>

b. GTM Tag for Purchase

  • Tag Type: Custom HTML
  • Trigger: Custom Event = purchase
  • HTML:
<script>
fbq('track', 'Purchase', {
value: {{DLV - ecommerce.value}},
currency: {{DLV - ecommerce.currency}},
contents: [],
content_type: 'product',
content_ids: [],
content_category: '',
num_items: 1,
order_id: {{DLV - ecommerce.transaction_id}}
});
</script>

🔹 6. Test Implementation

Use Facebook Pixel Helper Chrome Extension:

  • Verify events fire correctly
  • Look for PageView, AddToCart, and Purchase with parameters

🔹 7. Optional Events (for B2C or B2B flows)

Action Event Name
View Product ViewContent
Begin Checkout InitiateCheckout
Lead Form Submitted Lead

You can inject additional dataLayer.push() and replicate the tag logic accordingly.


📈 Bonus: Set Up Conversion API (Optional for Advanced Users)

Use server-side GTM to fire deduplicated events using event_id and Meta’s Conversions API to boost attribution accuracy. Let me know if you want the full server-side guide.


✅ Summary

Step Description
1 Add GTM to osCommerce
2 Add FB Pixel Base Code in GTM
3 Inject Data Layer for key eCommerce events
4 Create FB Event Tags (AddToCart, Purchase, etc.)
5 Test with Pixel Helper
6 Expand with optional B2B/B2C events

 

How to Anonymize PII While Maintaining Conversion Accuracy in OpenCart

Standard

Privacy regulations like GDPR, CCPA, and ePrivacy mandate the protection of Personally Identifiable Information (PII) in marketing and analytics platforms. But anonymizing user data doesn’t mean losing conversion accuracy.

🔐 What is Considered PII?

Data Type Classification Action Required
Email Address PII Hash or drop
Phone Number PII Hash or drop
IP Address Pseudonymous Mask or drop
Names PII Drop or hash (rare)


🧰 Prerequisites

Tool / Feature Description
OpenCart (3.x or 4.x) Your eCommerce platform
Google Tag Manager For data layer & tag handling
GA4, Meta, Ads For conversion attribution
SHA-256 Hash Function For hashing emails/phones
Consent Framework (optional) Compliant data handling


📦 Step 1: Hash PII Before Sending to GTM

Edit your success.twig or wherever you inject Data Layer variables.

<script>
function sha256(str) {
const encoder = new TextEncoder();
return crypto.subtle.digest('SHA-256', encoder.encode(str)).then(buf => {
return Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, '0')).join('');
});
}

const emailRaw = '{{ email | lower }}';
const phoneRaw = '{{ telephone | replace(" ", "") }}';

sha256(emailRaw).then(function(emailHash) {
sha256(phoneRaw).then(function(phoneHash) {
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'purchase',
email_hash: emailHash,
phone_hash: phoneHash,
transaction_id: '{{ order_id }}',
value: {{ order_total }},
currency: '{{ currency }}'
});
});
});
</script>

Note: This uses the browser-native crypto.subtle API for SHA-256.


🔄 Step 2: Pass Hashed Data to Tags in GTM

Example: Meta (Facebook) Advanced Matching

Tag Type: Custom HTML or Meta Pixel Tag
Trigger: purchase

<script>
fbq('track', 'Purchase', {
value: {{DL - value}},
currency: '{{DL - currency}}',
external_id: '{{DL - email_hash}}',
phone: '{{DL - phone_hash}}'
});
</script>


Example: GA4 User Properties (hashed email)

Tag Type: GA4 Event
User Properties:

Property Name Value
user_email {{DL - email_hash}}

You may also set this as a User Property in the GA4 Config tag.


🌐 Step 3: Anonymize IP Addresses in GA4

GA4 automatically anonymizes IPs by default, but for server-side implementations, ensure you’re not forwarding full IPs.

In server-side GTM, exclude IP address from request forwarding or mask using:

requestHeaders['x-forwarded-for'] = null;


🔁 Step 4: Consent-Controlled Exposure

If the user declines consent, don’t collect any PII—even hashed.

Add a check before pushing to the Data Layer:

if (window.consent_granted === true) {
dataLayer.push({
event: 'purchase',
email_hash: 'HASHED_EMAIL',
phone_hash: 'HASHED_PHONE'
});
}

Or use GTM Consent Mode v2 and only fire marketing tags with ad_user_data consent.


🧪 Step 5: QA & Validation

Check Tags:

Platform Tool to Test
Meta Facebook Pixel Helper
GA4 GA4 DebugView, Realtime tab
GTM Preview Mode, Variables tab
Network DevTools → Filter on collect

Ensure:

  • Only hashed data is sent
  • No plain text emails/phones in network payloads
  • Tags honor consent status


🧠 Strategic Tips

  • Hash client-side: Avoid sending raw PII to GTM or servers
  • Use same hashing method across tools to enable matching
  • Document hashing logic for audits
  • Rotate hashing logic if breach is suspected (advanced)


Consent Mode v2 Implementation in OpenCart Using GTM

Standard

With rising privacy regulations like GDPR, CCPA, and ePrivacy Directive, it’s crucial to implement Google Consent Mode v2 to control how tracking technologies behave based on user consent. In this article, you’ll learn how to implement Consent Mode v2 in OpenCart using Google Tag Manager (GTM) to comply with advertising requirements from Google, Meta, and others.

🎯 What Is Consent Mode v2?

Consent Mode v2 allows Google tags (like GA4, Ads, Floodlight) to adjust behavior based on user consent for:

  • ad_storage – for remarketing
  • analytics_storage – for analytics
  • ad_user_data – required by Google for EU traffic
  • ad_personalization – enables personalized ad delivery


🧰 Prerequisites

Tool Purpose
OpenCart 3.x or 4.x eCommerce CMS
Google Tag Manager For controlling all marketing pixels
Cookie Consent Manager e.g., Cookiebot, Complianz, OneTrust
GA4 & Google Ads Setup GA4/Ads tags in GTM


🧱 Step 1: Add Consent Initialization Tag in GTM

  1. Go to Tags > New
  2. Select Tag Type: “Consent Initialization – Google tag (gtag.js)”
  3. Configure with your GA4 and Google Ads IDs:

gtag('set', 'default_consent', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied'
});

Trigger: Consent Initialization – All Pages
⏱ Loads before any other tags.


🌐 Step 2: Set Up Consent Management Platform (CMP)

You can use any CMP that supports Consent Mode v2. Examples:

  • Cookiebot
  • OneTrust
  • Complianz
  • CookieYes

Example: Cookiebot Integration

  1. Sign up and configure domains
  2. Choose Google Consent Mode v2 compatible
  3. Copy the Cookiebot script

Paste this in your OpenCart header.twig:

<script id="Cookiebot" src="https://consent.cookiebot.com/uc.js" data-cbid="YOUR-ID" data-blockingmode="auto" type="text/javascript" async></script>


📦 Step 3: Configure Tags to Respect Consent

In GTM:

  • Open each tag (GA4, Google Ads, Meta Pixel, TikTok, etc.)
  • Scroll to “Consent Settings”
  • Enable “Require additional consent”
  • Add:

ad_storage
analytics_storage
ad_user_data
ad_personalization

This ensures tags don’t fire until the relevant consent is granted.


🧪 Step 4: Debug Consent Mode

Use Chrome Extension: Google Tag Assistant

Check:

Status Meaning
granted Consent granted – full tracking
denied Data collection limited
default_consent Applied if no choice made

Also test in GA4 > DebugView.


💬 Step 5: Optional — Custom Consent Tracking Event

Push a DataLayer event when user consents or rejects:

<script>
window.addEventListener("CookieConsentDeclaration", function() {
dataLayer.push({
event: "consent_updated",
ad_storage: Cookiebot.consents.given.marketing,
analytics_storage: Cookiebot.consents.given.statistics
});
});
</script>

You can trigger internal tags, call APIs, or log user behavior on consent action.


🔁 Step 6: GA4 Enhanced Measurement Compatibility

If using Enhanced Measurement in GA4:

  • Tags won’t collect PII or cookie data until analytics consent is granted.
  • Some events like page_view will still be sent in cookieless, anonymous mode.


📊 Optional: Fire Meta/Facebook & TikTok Pixel Respecting Consent

Wrap in GTM Custom HTML with conditional logic:

<script>
if (Cookiebot.consents.given.marketing) {
fbq('track', 'PageView');
ttq.track('ViewContent');
}
</script>

Or delay execution using Consent Triggers only when ad_storage is granted.


🔐 Server-Side Consent Propagation (Advanced)

If using Server-Side GTM, pass consent states as custom headers:

  • x-consent-ad_storage: granted
  • x-consent-analytics_storage: denied

Then route or suppress requests server-side accordingly.


📈 Strategic Benefits

  • Ensures compliance with GDPR & ePrivacy
  • Retains ad tracking while respecting user choice
  • Enables cookieless pings for attribution even when denied
  • Prevents tag bloat and duplicate event firing


Triggering Personalization Popups Based on GA4 Scroll + Exit Intent in OpenCart

Standard

Personalized popups—timed to user behavior like scroll depth or exit intent—are powerful tools for increasing engagement and conversions. By leveraging Google Tag Manager (GTM), GA4 events, and custom JavaScript in OpenCart, you can trigger popups at the right moment without third-party tools.

🧰 Prerequisites

Tool Purpose
OpenCart (3.x/4.x) eCommerce platform
GTM Web Container Implemented across site
GA4 Property For behavior tracking
Popup Framework Basic HTML/CSS/JS or tool like SweetAlert
Consent Management Optional (recommended)


🎯 Target Behavior Conditions

Trigger popups based on:

  • Scroll Depth: e.g. >60% of product page
  • Exit Intent: Cursor moves toward browser close button
  • Combined Conditions: Both scroll & exit in session


📦 Step 1: Add Scroll Depth Trigger in GTM

A. Enable Built-In Variables

Go to GTM > Variables > Enable:

  • Scroll Depth Threshold
  • Scroll Direction

B. Create a Scroll Trigger

  • Trigger Type: Scroll Depth
  • Vertical Scroll Depths: 60, 80
  • Pages: Page Path matches RegEx e.g. /product

C. Tag: GA4 Scroll Event

  • Tag Type: GA4 Event
  • Event Name: scroll_depth
  • Event Parameters:
    • scroll_percent: {{Scroll Depth Threshold}}
    • page_path: {{Page Path}}


🌐 Step 2: Detect Exit Intent with Custom HTML Tag

Create a Custom HTML tag in GTM:

<script>
(function() {
let fired = false;
document.addEventListener("mouseout", function(e) {
if (!fired && e.clientY < 0) {
fired = true;
window.dataLayer = window.dataLayer || [];
dataLayer.push({ event: 'exit_intent' });
}
});
})();
</script>

Trigger: All Pages (or specific to product/cart pages)


💬 Step 3: Show Personalized Popup on Scroll + Exit

You can trigger a popup only when both scroll & exit intent have occurred.

A. Create Custom Event Variables in GTM

  • event.scroll_depth_triggered = 1 (when scroll event fires)
  • event.exit_intent_triggered = 1 (when exit intent fires)

B. Setup Trigger Logic

  1. In GTM, create 2 custom triggers:

  • Trigger A: Fires event.scroll_depth → pushes variable
  • Trigger B: Fires event.exit_intent → pushes variable

  1. Create a Custom HTML Tag:

<script>
if (window.scroll_depth_triggered && window.exit_intent_triggered) {
document.querySelector('#my-exit-popup').style.display = 'block';
}
</script>

Or, use a library:

<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script>
if (window.scroll_depth_triggered && window.exit_intent_triggered) {
Swal.fire({
title: 'Leaving so soon?',
text: 'Grab 10% off before you go!',
icon: 'info',
confirmButtonText: 'Apply Code'
});
}
</script>


🛒 Step 4: Personalize Popup by Page

Use {{Page Path}} or {{DL - product_id}} to personalize:

Swal.fire({
title: 'Still thinking about {{DL - product_name}}?',
text: 'Get 10% off today!',
confirmButtonText: 'Buy Now'
});

You can pull product ID, category, or cart value from the Data Layer to tailor your offer.


📊 Step 5: Track Popup Views in GA4

Send GA4 events when popup is shown and clicked.

GA4 Event Tag – Popup Shown:

  • Event Name: popup_shown
  • Parameters:
    • page_type: product
    • trigger_type: scroll_exit_combo

GA4 Event Tag – Popup Clicked:

Use a Custom Event Trigger when popup button is clicked, then push:

dataLayer.push({ event: 'popup_clicked', trigger_type: 'scroll_exit_combo' });

Track that in GA4 with another event tag.


🔐 Step 6: Consent-Mode Safe (Optional)

Wrap popup and GA4 events with a consent check:

if (window.consent_granted === true) {
dataLayer.push({ event: 'popup_shown' });
}


🧪 Step 7: QA + Debugging

Tool Use
GTM Preview Mode Check firing of both events
GA4 DebugView Validate scroll/exit events
Browser Console Test popup firing logic


📈 Strategic Use Cases

Use Case Example Behavior
Cart Abandoners Show exit popup w/ discount
Product Page Lurkers Scroll + no add-to-cart
Mobile Browsers >80% scroll Mobile-specific lead capture
Exit on Checkout Page Show trust-building popup


Firing Multi-Platform Pixels (Meta, TikTok, Pinterest) from a Single GTM Tag

Standard

Managing multiple ad pixels across Meta (Facebook), TikTok, and Pinterest can quickly become chaotic—especially when duplicate tags, inconsistent variables, or messy triggers bloat your GTM container. This article explains how to fire multiple pixel events from a single GTM Custom HTML tag, dynamically injecting platform-specific logic while maintaining speed, accuracy, and deduplication.


🧰 Prerequisites

Tool/Platform Purpose
Google Tag Manager Web container
Meta Pixel ID For Facebook/Instagram tracking
TikTok Pixel ID For TikTok Ads
Pinterest Tag ID For Pinterest Ads
Consent Management (Optional) For compliant firing logic


✅ Use Case

Fire a unified Purchase event to:

  • Meta Pixel (and/or CAPI)
  • TikTok Pixel
  • Pinterest Tag

From one GTM tag after a successful checkout.


📦 Step 1: Push Unified DataLayer on Checkout

In success.twig (or similar confirmation page):

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'purchase',
transaction_id: '{{ order_id }}',
value: {{ order_total }},
currency: '{{ currency }}',
content_ids: [{% for product in products %}'{{ product.product_id }}',{% endfor %}],
content_name: '{{ store_name }}',
content_type: 'product_group'
});
</script>


🌐 Step 2: Create a Single Custom HTML Tag in GTM

Tag Type: Custom HTML
Trigger: Custom Event = purchase

<script>
// ========== Meta Pixel ==========
fbq('track', 'Purchase', {
value: {{DL - value}},
currency: '{{DL - currency}}',
content_ids: {{DL - content_ids}},
content_type: '{{DL - content_type}}'
});

// ========== TikTok Pixel ==========
ttq.track('CompletePayment', {
contents: [{id: {{DL - content_ids}}, quantity: 1}],
value: {{DL - value}},
currency: '{{DL - currency}}'
});

// ========== Pinterest Tag ==========
pintrk('track', 'checkout', {
value: {{DL - value}},
order_id: '{{DL - transaction_id}}',
currency: '{{DL - currency}}'
});
</script>

Important:

  • Use {{DL - variable}} to reference GTM variables tied to your Data Layer (e.g., DLV - transaction_id)
  • Make sure all variables are defined in GTM using Data Layer Variable type


🧪 Step 3: Load Pixel Base Codes Conditionally

In separate tags, add pixel base codes and trigger them on All Pages or via consent logic.

Meta Pixel Base

<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);
t.async=!0;t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');

fbq('init', 'YOUR_META_PIXEL_ID');
</script>

TikTok Pixel Base

<script>
!function (w, d, t) {
w.TiktokAnalyticsObject = t;
var ttq = w[t] = w[t] || [];
ttq.methods = ["page", "track", "identify", "instances", "debug", "on", "off", "once", "ready", "alias", "group", "enableCookie", "disableCookie"];
ttq.setAndDefer = function (t, e) { t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } };
for (var i = 0; i < ttq.methods.length; i++) ttq.setAndDefer(ttq, ttq.methods[i]);
ttq.instance = function (t) {
var e = ttq._i[t] || [];
for (var n = 0; n < ttq.methods.length; n++
)ttq.setAndDefer(e, ttq.methods[n]);
return e
};
ttq.load = function (e, n) {
var i = "https://analytics.tiktok.com/i18n/pixel/events.js";
ttq._i = ttq._i || {};
ttq._i[e] = [];
ttq._i[e]._u = i;
ttq._t = ttq._t || {};
ttq._t[e] = +new Date;
ttq._o = ttq._o || {};
ttq._o[e] = n || {};
var o = document.createElement("script");
o.type = "text/javascript";
o.async = !0;
o.src = i + "?sdkid=" + e + "&lib=" + t;
var a = document.getElementsByTagName("script")[0];
a.parentNode.insertBefore(o, a)
};

ttq.load('YOUR_TIKTOK_PIXEL_ID');
ttq.page();
}(window, document, 'ttq');
</script>

Pinterest Base

<script>
!function(e){if(!window.pintrk){window.pintrk=function(){window.pintrk.queue.push(Array.prototype.slice.call(arguments))};var n=window.pintrk;n.queue=[],n.version="3.0";var t=document.createElement("script");t.async=!0,t.src=e;var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r)}}("https://s.pinimg.com/ct/core.js");

pintrk('load', 'YOUR_PINTEREST_TAG_ID');
pintrk('page');
</script>


🔐 Step 4: Consent-Aware Triggering (Optional)

To comply with privacy laws, wrap your multi-pixel script logic in consent-based triggers:

<script>
if (window.consent_granted === true) {
// fire fbq, ttq, pintrk tracking
}
</script>

Or use GTM’s Consent Mode v2, enabling this tag only if "ad_storage" and "analytics_storage" are granted.


🧪 Step 5: QA Tools

Tool Use Case
GTM Preview Tag firing and variable check
Meta Pixel Helper (Chrome) Check Facebook events
TikTok Pixel Helper Confirm TikTok event transmission
Pinterest Tag Helper Validate Pinterest events
Network tab (DevTools) Verify request payloads


🧠 Pro Tips

  • Use a lookup table to manage different event names per platform (e.g., purchaseCompletePayment)
  • Consolidate content_ids, prices, and categories in a unified ecommerce object
  • For server-side GTM, replicate this logic as server events via API endpoints


Dynamic Email List Segmentation with OpenCart Events via GTM & GA4

Standard

Dynamic email segmentation allows marketers to tailor campaigns based on real-time user actions. By capturing OpenCart behavioral events via Google Tag Manager (GTM) and pushing them to GA4, you can build highly-relevant email segments using CRM tools like Klaviyo, Mailchimp, or HubSpot through GA4 audiences or server-side syncs.


🧰 Prerequisites

Requirement Details
OpenCart 3.x / 4.x Your eCommerce platform
Google Tag Manager Web container implemented on OpenCart
Google Analytics 4 Connected to GTM
Email Platform (CRM) e.g., Klaviyo, Mailchimp, HubSpot, etc.
Consent Framework Optional, for GDPR/CCPA compliance


🎯 Objective

Segment users for email campaigns like:

  • Viewed product but did not buy
  • Abandoned cart after 1+ item
  • Completed checkout for specific category
  • Returning users with no purchase in last 14 days


📦 Step 1: Inject DataLayer Events in OpenCart

A. Product View

In product.twig:

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'view_item',
ecommerce: {
items: [{
item_id: '{{ product_id }}',
item_name: '{{ heading_title }}',
category: '{{ category }}',
price: {{ price }}
}]
}
});
</script>


B. Add to Cart

In cart button JS or via GTM click listener:

dataLayer.push({
event: 'add_to_cart',
ecommerce: {
items: [{
item_id: '123',
item_name: 'Demo Product',
price: 29.99
}]
}
});


C. Checkout Start

In checkout.twig:

<script>
dataLayer.push({
event: 'begin_checkout'
});
</script>


D. Purchase

In success.twig:

<script>
dataLayer.push({
event: 'purchase',
user_email: '{{ email | lower }}',
transaction_id: '{{ order_id }}',
ecommerce: {
transaction_id: '{{ order_id }}',
value: {{ order_total }},
currency: '{{ currency }}',
items: [{ item_id: '{{ product_id }}' }]
}
});
</script>


🌐 Step 2: Capture & Send Events to GA4

In GTM, create a tag for each of the following:

  • Tag Type: GA4 Event
  • Event Name: match view_item, add_to_cart, etc.
  • Event Parameters:
    • items: from ecommerce.items
    • user_email: from dataLayer

🔁 Add all event tags for:

  • view_item
  • add_to_cart
  • begin_checkout
  • purchase

Make sure your GA4 Config Tag is referenced.


🧲 Step 3: Build Email Segments from GA4 Audiences

In GA4 > Admin > Audiences:

A. Cart Abandoners

  • Include users who fired add_to_cart
  • Exclude users who completed purchase
  • Time limit: 3 days

B. Product Viewers (No Cart)

  • view_item event triggered
  • No add_to_cart in 7 days

C. Loyal Buyers (Email campaigns for upsell)

  • 2+ purchases in last 30 days
  • Include item category or price thresholds

These GA4 audiences can be pushed to:

  • Google Ads (for Gmail Ads)
  • Exported to BigQuery or CRM


🔀 Step 4: Sync to Email Platforms

Option 1: CRM Integration (Klaviyo, HubSpot, Mailchimp)

Use GA4 → BigQuery → API to:

  • Export user email + behavior
  • Create segments in your email tool dynamically

Example logic for API sync:

{
"email": "user@example.com",
"last_event": "add_to_cart",
"category": "Books",
"cart_value": 45.99
}

Alternatively, use Zapier or GCP Functions to automate nightly sync from GA4 audience exports.


🔐 Step 5: Respect User Consent

To delay event tags and email PII sync until consent:

if (window.consent_granted === true) {
dataLayer.push({
event: 'purchase',
user_email: '{{ email }}'
});
}

Or use GTM’s Consent Initialization trigger + Consent Mode v2.


🧪 Step 6: Debugging

Tool Use
GTM Preview Mode Confirm tag firing and variable passing
GA4 DebugView Validate event stream + parameters
Email CRM Logs Check audience match + campaign trigger


📈 Example Use Cases

Segment Name Trigger Logic
Abandoned Cart 24h add_to_cart but no purchase in 1 day
Repeat Visitors session_start 3+ times, no conversion
High-Value Buyers purchase with value > 100
Product Browsers view_item 2+ times on category = Electronics


Creating Behavior-Based Audiences in GA4 for OpenCart Remarketing

Standard

Google Analytics 4 (GA4) allows you to build highly-targeted behavior-based audiences for retargeting in Google Ads. When integrated with OpenCart, GA4 can segment users based on their interactions—such as product views, cart activity, or checkout behavior—and send these audiences to Google Ads for remarketing.

🧰 Prerequisites

Requirement Description
OpenCart 3.x or 4.x Your eCommerce platform
GA4 Property Installed via GTM
Google Tag Manager Web container active on OpenCart
Google Ads Account Linked to GA4 (for remarketing)
Consent Management Recommended for compliant tracking


🧱 Step 1: Inject Custom Events into OpenCart

A. Product Detail Page – view_item

In product.twig:

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'view_item',
ecommerce: {
items: [{
item_id: '{{ product_id }}',
item_name: '{{ heading_title }}',
item_category: '{{ category }}',
price: {{ price }},
quantity: 1
}]
}
});
</script>


B. Add to Cart Event – add_to_cart

In your JS click handler or via GTM click trigger:

dataLayer.push({
event: 'add_to_cart',
ecommerce: {
items: [{
item_id: '123',
item_name: 'Sample Product',
price: 19.99,
quantity: 1
}]
}
});


C. Begin Checkout – begin_checkout

In checkout.twig:

<script>
dataLayer.push({
event: 'begin_checkout',
ecommerce: {
items: [{
item_id: '{{ item_id }}',
item_name: '{{ name }}',
price: '{{ price }}',
quantity: 1
}]
}
});
</script>


📦 Step 2: Configure GA4 Tags in GTM

For each custom event above:

  1. Tag Type: GA4 Event
  2. Configuration Tag: Your GA4 ID tag
  3. Event Name: Match view_item, add_to_cart, etc.
  4. Event Parameters:
    • items: Use a Data Layer Variable that holds ecommerce.items

Example – GA4 Add to Cart Tag

  • Event Name: add_to_cart
  • Parameters:
    • items = {{DLV - ecommerce.items}}

✅ Repeat this for all funnel steps: view_item, add_to_cart, begin_checkout, purchase


🔄 Step 3: Enable Google Ads Remarketing via GA4

  1. Go to GA4 > Admin > Product Links > Google Ads
  2. Link your Google Ads account
  3. Enable the checkbox: “Enable Personalized Advertising”


🧲 Step 4: Create Audiences in GA4

A. Viewers But No Cart

Condition:

  • Event = view_item
  • AND does not include event = add_to_cart within last 7 days

B. Cart Abandoners

Condition:

  • Event = add_to_cart
  • AND not purchase within 3 days

C. Checkout Starters, No Purchase

Condition:

  • Event = begin_checkout
  • AND not purchase within 1 day


🛠 Step 5: Send Audiences to Google Ads

Once the Google Ads link is active:

  • Go to GA4 > Admin > Audiences
  • Click into your audience → Enable “Google Ads Audience Activation”
  • These audiences will now appear in Google Ads > Tools > Audience Manager

Use them in campaigns like:

  • Dynamic Display Ads
  • Performance Max
  • Standard Remarketing Campaigns


🔐 Step 6: Consent Mode (Optional)

To delay audience data collection until user consent:

  • Set up GTM Consent Mode
  • Delay GA4 event tags until "analytics_storage" is granted
  • Example:

<script>
if (window.consent_granted === true) {
dataLayer.push({ event: 'view_item', ecommerce: { ... }});
}
</script>


🧪 Step 7: QA & Debugging

Tool Use Case
GTM Preview Mode Validate event payloads
GA4 DebugView Inspect events in real-time
Google Ads Audience Check audience size over time


🎯 Strategic Benefits

  • Build precise retargeting funnels from behavioral triggers
  • Engage non-converting users with custom creative
  • Feed audiences to multiple Google Ads formats
  • Zero reliance on 3rd-party cookies (first-party GA4 data only)