Passing OpenCart Checkout Events Server-Side for Ads & Analytics Accuracy

Standard

In a privacy-first era of ad tracking and analytics, client-side tracking alone is no longer enough. OpenCart stores often suffer from lost conversion data, especially due to:

  • Cookie restrictions (iOS, browsers)
  • Ad blockers
  • Delayed pixel firing

Server-side tracking of checkout events solves these issues by passing key signals like begin_checkout, add_payment_info, and purchase directly from your server to platforms like Google Ads, GA4, Meta, etc.

✅ What You’ll Achieve

Event Tracked Server-Side
begin_checkout Yes
add_payment_info Yes
purchase Yes
Conversion Value Accurate and secure
Email/Phone Hashed PII for matching
Deduplication Using event_id


🧰 Prerequisites

Requirement Notes
OpenCart (3.x / 4.x) Theme + controller access
Web & Server GTM Installed and connected
GA4, Google Ads, Meta Pixel Ready with Measurement ID / Tag ID
HTTPS Domain Required for sending hashed data
Optional: Consent Layer To handle PII lawfully in the EU/US


📦 Step 1: Add Checkout Step Events in Controller

Edit: catalog/controller/checkout/checkout.php

Add a push for begin_checkout when user lands on the checkout page:

$data['ss_begin_checkout'] = json_encode([
'event' => 'begin_checkout',
'event_id' => uniqid('ss_checkout_', true)
]);

Then in checkout.twig, inject:

{% if ss_begin_checkout %}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ ss_begin_checkout|raw }});
</script>
{% endif %}

Repeat similarly in catalog/controller/checkout/confirm.php:

$data['ss_add_payment_info'] = json_encode([
'event' => 'add_payment_info',
'event_id' => uniqid('ss_payment_', true)
]);

And inject into the appropriate confirmation step view template:

{% if ss_add_payment_info %}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ ss_add_payment_info|raw }});
</script>
{% endif %}


🧾 Step 2: Finalize purchase Event in success.php

In catalog/controller/checkout/success.php:

$order_id = $this->session->data['order_id'];
$order_info = $this->model_checkout_order->getOrder($order_id);
$products = $this->model_checkout_order->getOrderProducts($order_id);

$email = strtolower(trim($order_info['email']));
$phone = preg_replace('/\D/', '', $order_info['telephone']);

$items = [];
foreach ($products as $product) {
$items[] = [
'item_id' => $product['model'],
'item_name' => $product['name'],
'price' => $product['price'],
'quantity' => $product['quantity']
];
}

$data['ss_purchase'] = json_encode([
'event' => 'purchase',
'transaction_id' => $order_id,
'currency' => $order_info['currency_code'],
'value' => $order_info['total'],
'email' => hash('sha256', $email),
'phone' => hash('sha256', $phone),
'items' => $items,
'event_id' => uniqid('ss_purchase_', true)
]);

In success.twig:

{% if ss_purchase %}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ ss_purchase|raw }});
</script>
{% endif %}


🚀 Step 3: Forward Checkout Events to ssGTM

In Web GTM, add a Custom HTML Tag:

<script>
fetch('https://gtm.yourdomain.com/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event_name: '{{DL - event}}',
event_id: '{{DL - event_id}}',
email: '{{DL - email}}',
phone: '{{DL - phone}}',
transaction_id: '{{DL - transaction_id}}',
value: '{{DL - value}}',
currency: '{{DL - currency}}',
items: {{DL - items}}
})
});
</script>

Trigger: All Custom Events matching begin_checkout, add_payment_info, or purchase.


🛰️ Step 4: Setup ssGTM Tags for GA4 & Google Ads

GA4 Event Tag (in Server GTM)

  • Event Name: purchase, begin_checkout, or add_payment_info
  • Measurement ID: From GA4
  • Parameters:
    • event_id, transaction_id, value, currency, items

Google Ads Conversion Tag (Server)

  • Conversion ID / Label
  • Email / Phone (hashed)
  • Event ID
  • Value / Currency / Transaction ID

Deduplication: Use event_id across both web and server tags.


🔐 Step 5: Optional — Consent Compliance

In Web GTM, conditionally fire fetch tag only if consent is granted using:

if (window.gtag && gtag.get('consent', 'ad_storage') === 'granted') {
// send fetch
}


✅ Step 6: Testing

Tool Check
GTM Preview Ensure event pushes occur
Server GTM Preview Confirm forwarded data
GA4 DebugView Look for real-time hits
Google Ads Tag Diagnostics Check deduplication
Meta Events Manager (if implemented) For CAPI validation


📊 Benefits Recap

Feature Benefit
Server-Side Purchase Tracking Higher attribution accuracy
Hashed PII Matches even when cookies fail
Event Deduplication Prevents inflated metrics
Checkout Stage Monitoring Funnel drop-off analysis
Ads Platform Integration Better optimization and ROAS


Server-Side GTM Implementation for OpenCart with GA4 and Google Ads

Standard

Server-Side Google Tag Manager (ssGTM) is the modern foundation for privacy-safe and robust tracking in OpenCart. By shifting tracking logic from browsers to a secure server, you gain:

  • Improved conversion accuracy
  • Protection against ad blockers
  • Compliance with consent regulations
  • Seamless integration with GA4 and Google Ads (including Enhanced Conversions)


🎯 Goal

Track key eCommerce events in OpenCart (like purchase, add_to_cart, view_item) through Web GTM → ssGTM → GA4 & Google Ads, with deduplication and first-party data.


🧰 Prerequisites

Requirement Notes
OpenCart 3.x/4.x FTP and theme access required
GTM Web Container Installed on all frontend pages
GTM Server Container Hosted with custom subdomain (e.g., gtm.yoursite.com)
GA4 & Google Ads Measurement IDs and Conversion Labels ready
Consent System (optional) For GDPR compliance


🧱 Step 1: Setup Web GTM Container in OpenCart

Edit catalog/view/theme/*/template/common/header.twig:

<!-- 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 GTM -->

Repeat similar for <noscript> tag inside <body>.

✅ Web GTM is now active on your OpenCart frontend.


🔐 Step 2: Configure Server GTM on Custom Subdomain

  1. Set up a subdomain like: gtm.yoursite.com
  2. Point DNS to GTM server IP or use App Engine/Cloud Run
  3. Deploy GTM Server Container
  4. Enable GA4 and Google Ads built-in clients
  5. Update Web GTM → GA4 Config Tag to point to server container:

transport_url: 'https://gtm.yoursite.com'


🛒 Step 3: Push DataLayer Events in OpenCart

Example: Purchase Event (in success.php)

$order_id = $this->session->data['order_id'];
$order_info = $this->model_checkout_order->getOrder($order_id);
$products = $this->model_checkout_order->getOrderProducts($order_id);

$email = strtolower(trim($order_info['email']));
$phone = preg_replace('/\D/', '', $order_info['telephone']);

$items = [];
foreach ($products as $product) {
$items[] = [
'item_id' => $product['model'],
'item_name' => $product['name'],
'price' => $product['price'],
'quantity' => $product['quantity'],
];
}

$data['ss_purchase'] = json_encode([
'event' => 'purchase',
'transaction_id' => $order_id,
'currency' => $order_info['currency_code'],
'value' => $order_info['total'],
'email' => hash('sha256', $email),
'phone' => hash('sha256', $phone),
'items' => $items,
'event_id' => uniqid('ss_', true)
]);

In success.twig:

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ ss_purchase|raw }});
</script>


🧩 Step 4: GA4 Configuration in Web GTM (With Server Transport)

Tag Type: GA4 Configuration
Fields to Set:

Field Value
Measurement ID G-XXXXXXXXXX
transport_url https://gtm.yoursite.com

✅ This tells GA4 events to route through your server.


⚙️ Step 5: GA4 Event Tag (e.g., purchase)

Event Name: purchase
Event Parameters:

  • transaction_id: {{DL - transaction_id}}
  • value: {{DL - value}}
  • currency: {{DL - currency}}
  • items: {{DL - items}}

✅ Trigger on Custom Event = purchase


🔁 Step 6: Google Ads Conversion Tag (Client & Server)

Web GTM Google Ads Tag

  • Conversion ID: AW-XXXXXXXXX
  • Conversion Label: ABCD1234XYZ
  • Include event_id: {{DL - event_id}}

✅ Use same event_id for deduplication.


🛰️ Step 7: Forward Events to Server-Side GTM

In Web GTM, use a tag (or modify GA4 tag) to send event_id, email, phone via headers or body using:

fetch('https://gtm.yoursite.com/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event_name: 'purchase',
email: '{{DL - email}}',
phone: '{{DL - phone}}',
event_id: '{{DL - event_id}}',
value: '{{DL - value}}',
currency: '{{DL - currency}}',
transaction_id: '{{DL - transaction_id}}',
items: {{DL - items}},
gclid: '{{url - gclid}}'
})
});

✅ Forwarded to your Server GTM container.


📦 Step 8: Setup GA4 and Google Ads Tags in Server GTM

GA4 Tag in ssGTM:

Field Value
Measurement ID G-XXXXXXXXXX
Event Name purchase
Event ID {{event_id}}
Parameters items, value, currency, etc.

Google Ads Tag in ssGTM:

Field Value
Conversion ID Your Google Ads ID
Conversion Label Label from Ads Manager
Email & Phone {{email}}, {{phone}} (hashed)
Event ID Same as client side
GCLID If available


📊 Step 9: Verify & Test

Tool Purpose
GTM Preview Mode Validate dataLayer & event_id
Server GTM Preview Confirm requests arrive
GA4 DebugView Real-time confirmation
Google Ads → Conversions → Diagnostics Check for deduplication success


🔁 Deduplication Strategy

Ensure the same event_id is used:

  • In Web Pixel (client-side)
  • In Server CAPI (server-side)

→ Meta, GA4, and Google Ads will automatically deduplicate.


🔐 Consent Strategy (Optional but Recommended)

Add ad_storage, analytics_storage consent flags in dataLayer or server headers to comply with GDPR/CCPA.


OpenCart Conversion Optimization Using GA4 Exploration Reports

Standard

In the evolving landscape of digital analytics, understanding how users interact across your OpenCart store is essential to optimizing conversion funnels. GA4 Exploration Reports unlock that power by going beyond standard reporting and providing granular behavioral insights — especially when paired with Enhanced eCommerce and custom tracking via GTM.

🎯 Why GA4 Exploration Reports Matter

Unlike Universal Analytics, GA4 provides Exploration Reports to help you:

  • Build custom conversion funnels
  • Understand user paths and loopbacks
  • Analyze segment behavior overlaps
  • Compare custom metrics and dimensions

When properly configured with OpenCart + GTM, you’ll uncover deep CRO insights.


🧰 Requirements

Tool/Platform Notes
OpenCart 3.x or 4.x With admin and FTP access
Google Tag Manager Web container installed
GA4 Property Connected to GTM
Enhanced eCommerce Must be implemented
Custom Events Recommended for CTA clicks, scrolls, etc.


🧱 Step 1: Implement GA4 Enhanced eCommerce in OpenCart

Use GTM to send the following events from OpenCart:

  • view_item
  • add_to_cart
  • begin_checkout
  • purchase

Example: Data Layer Push on Product Page

In catalog/controller/product/product.php:

$this->load->model('catalog/product');
$product_info = $this->model_catalog_product->getProduct($product_id);

$data['dl_product_view'] = json_encode([
'event' => 'view_item',
'ecommerce' => [
'items' => [[
'item_id' => $product_info['model'],
'item_name' => $product_info['name'],
'price' => $product_info['price'],
'category' => $product_info['category'],
'quantity' => 1
]]
]
]);

In product.twig:

{% if dl_product_view %}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ dl_product_view|raw }});
</script>
{% endif %}

Repeat similar steps for cart, checkout, and success pages.


⚙️ Step 2: Enable GA4 Tags in GTM

  1. Create GA4 Configuration Tag
  2. For each event (view_item, add_to_cart, etc.), create:
    • GA4 Event Tag
    • Triggered by corresponding Custom Event (view_item, etc.)
    • Event Parameters:
      • items: {{DL - ecommerce.items}}
      • value, currency, etc. as needed

✅ Now, all purchase journey data is flowing into GA4.


💡 Step 3: Track Micro-Conversions (CTA, Scroll, Engagement)

Example: Scroll Depth Tracking

In product.twig:

<script>
document.addEventListener('scroll', function() {
if ((window.scrollY + window.innerHeight) / document.body.scrollHeight > 0.75) {
dataLayer.push({ event: 'scroll_75' });
}
}, { once: true });
</script>

In GTM:

  • Trigger: Custom Event = scroll_75
  • Tag: GA4 Event scroll_engagement


📈 Step 4: Mark Conversions in GA4 Admin

  1. Go to Admin → Events
  2. Mark as conversion:
    • purchase
    • begin_checkout
    • cta_click (optional)
    • scroll_engagement (optional)


🔍 Step 5: Create Funnel Exploration Reports in GA4

Go to Explore → Funnel Exploration → Create New

Example Funnel:

Step Event Name
1 view_item
2 add_to_cart
3 begin_checkout
4 purchase

Settings:

  • Open Funnel: ✅
  • Breakdown: By device, channel, product category
  • Segment: Users from mobile/organic vs desktop/paid


🔄 Step 6: Create Path Exploration Reports

Explore → Path Exploration → Start from session_start

Path Analysis Ideas:

  • Identify drop-off loops (e.g., cart → home → cart)
  • Find abandoned checkout sequences
  • Discover exit patterns after view_item


🔗 Step 7: Add Custom Dimensions for CTA or Variant Testing

Track CTA versions via a custom dimension:

dataLayer.push({
event: 'cta_click',
cta_text: 'Buy Now – Variant A'
});

In GA4:

  • Register cta_text as a custom dimension
  • Use Free Form reports to analyze CTR by CTA type


🧠 Step 8: Use Segment Overlap to Compare Behavior

Use Explore → Segment Overlap to compare:

  • Users who clicked CTA but didn’t purchase
  • Mobile vs Desktop engagement behavior
  • Returning users who added to cart


🧪 Step 9: QA and Validate

Step Method
Tag Validation Use GTM Preview Mode
Data Validation Use GA4 DebugView
Path/Funnel Integrity Test live purchase journey
Report QA Use GA4 → Explore


📊 Sample Report Insights You Can Act On

Insight Optimization
High view_item → low add_to_cart Add trust badges, reviews, pricing clarity
Users loop cart → home → cart Add sticky checkout buttons
Organic users drop at checkout Improve form UX and autofill support


🧩 Bonus Tip: Link GA4 to BigQuery

Export GA4 data to BigQuery for advanced cohort, attribution, and LTV analysis.


📦 Architecture Overview

OpenCart Theme → GTM Push Events → GA4 Capture → Exploration Analysis → CRO Action


📊 Tracking Product List Clicks, Impressions, and Detail Views in GA4

Standard

GA4 Enhanced Ecommerce allows you to track every touchpoint across a customer’s product discovery journey. For OpenCart (or any eCommerce platform), capturing product list impressions, clicks, and detail views is crucial for measuring product exposure and user engagement.

✅ Why Track Product List Interactions?

Metric Insight
Product impressions Measure visibility across carousels or listings
Product clicks Determine which items are drawing attention
Product detail views See what earns deeper interest
Click-through rate (CTR) Identify which products convert from list views

🧰 Requirements

  • GA4 with GTM installed
  • Dynamic rendering of product lists (e.g., homepage, category page, etc.)
  • Access to .twig or template files
  • Consent mode implemented (recommended for EU compliance)

🚀 Step-by-Step Implementation


🔹 Step 1: Push Product List Impressions to dataLayer

In your category or homepage .twig file, loop through products like this:

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'view_item_list',
ecommerce: {
item_list_name: '{{ heading_title }}',
items: [
{% for product in products %}
{
item_id: '{{ product.model }}',
item_name: '{{ product.name|escape('js') }}',
price: '{{ product.price|replace({'$': '', ',': ''}) }}',
index: {{ loop.index }},
item_list_name: '{{ heading_title }}'
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}
});
</script>

✅ This pushes a view_item_list event to the dataLayer whenever a list is rendered.


🔹 Step 2: Push Clicks on Products in the List

Wrap each product card or link with a click listener that pushes a select_item event.

Example (inside each product loop):

<a href="{{ product.href }}" class="product-card" 
onclick="dataLayer.push({
event: 'select_item',
ecommerce: {
item_list_name: '{{ heading_title }}',
items: [{
item_id: '{{ product.model }}',
item_name: '{{ product.name|escape('js') }}',
price: '{{ product.price|replace({'$': '', ',': ''}) }}',
index: {{ loop.index }},
item_list_name: '{{ heading_title }}'
}]
}
})">
<img src="{{ product.thumb }}" alt="{{ product.name }}" />
<span>{{ product.name }}</span>
</a>

✅ This sends a select_item event on click, preserving context like index and list name.


🔹 Step 3: Push Product Detail Views

On the product detail page (product.twig):

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'view_item',
ecommerce: {
items: [{
item_id: '{{ product.model }}',
item_name: '{{ product.name|escape('js') }}',
price: '{{ product.price|replace({'$': '', ',': ''}) }}',
item_category: '{{ category_name }}',
item_list_name: '{{ referring_list_name|default('Product Page') }}'
}]
}
});
</script>

✅ This sends a view_item event to GA4, capturing the actual detail page view.


🔹 Step 4: Create GA4 Event Tags in GTM

For each interaction:

1. view_item_list

  • Tag Type: GA4 Event
  • Event Name: view_item_list
  • Parameters:
    • item_list_name: {{DLV - ecommerce.item_list_name}}
    • items: {{DLV - ecommerce.items}}
  • Trigger: Custom Event → view_item_list

2. select_item

  • Tag Type: GA4 Event
  • Event Name: select_item
  • Parameters:
    • item_list_name: {{DLV - ecommerce.item_list_name}}
    • items: {{DLV - ecommerce.items}}
  • Trigger: Custom Event → select_item

3. view_item (product page)

  • Tag Type: GA4 Event
  • Event Name: view_item
  • Parameters:
    • items: {{DLV - ecommerce.items}}
  • Trigger: Custom Event → view_item

🔹 Step 5: Create Data Layer Variables in GTM

Create these Data Layer Variables:

Variable DLV Name
DLV – ecommerce.items ecommerce.items
DLV – ecommerce.item_list_name ecommerce.item_list_name

✅ These will populate event parameters in your GA4 event tags.


🔹 Step 6: Verify in GA4 DebugView

  • Navigate to your product list or homepage
  • Watch for:
    • view_item_list on list load
    • select_item on click
    • view_item on detail page

Make sure GA4 receives the correct structure under ecommerce.items.


🔹 Step 7: Analyze List Performance in GA4

Go to Explore → Free Form or Funnel:

Suggested Funnel:

  1. view_item_list
  2. select_item
  3. view_item
  4. add_to_cart
  5. purchase

Breakdown by:

  • item_list_name
  • item_name
  • device category
  • source/medium

🧠 Pro Tips

Tip Why It Matters
Include index in each item Enables CTR measurement
Track multiple carousels with item_list_name Compare visibility across homepage, category, and upsells
Use product.model as item_id Matches Merchant Center feed
Escape product names Prevents JS injection
Leverage select_item + view_item For full pre-cart journey analysis

🧪 QA Checklist

Action
Product list triggers view_item_list
Product clicks push select_item
Product pages fire view_item
GA4 DebugView shows correct values
Tags configured and firing in GTM

📦 Summary Table

GA4 Event Description Triggered On
view_item_list List impression Homepage / Category page
select_item Product click Product card anchor click
view_item Product detail page view Product detail page

🧾 Measuring Checkout Drop-offs in osCommerce Using GA4 Events (Step-by-Step + Code)

Standard

Checkout abandonment is one of the biggest friction points in any ecommerce funnel. For osCommerce stores, tracking checkout drop-offs using GA4 events allows store owners and marketers to identify exactly where users abandon the flow—and optimize accordingly.

In this guide, you’ll learn how to track each checkout step, send GA4-compatible events via GTM, and build a drop-off analysis funnel to improve conversion rates.

🎯 Goals of This Implementation

  • Track entry into each checkout step (shipping, billing, payment, confirmation)
  • Capture user abandonment/drop-off between steps
  • Segment drop-offs by device, source, product, etc.
  • Enable targeted CRO and remarketing strategies

🧰 Prerequisites

  • Google Tag Manager installed on all osCommerce pages
  • GA4 Configuration Tag created in GTM
  • osCommerce’s checkout process has multiple step pages (e.g., checkout_shipping.php, checkout_payment.php, checkout_confirmation.php, checkout_success.php)

🛒 Step 1: Identify Checkout Steps in osCommerce

Typical osCommerce checkout pages:

Step File in osCommerce GA4 Event to Use
Step 1: Shipping checkout_shipping.php begin_checkout
Step 2: Payment Info checkout_payment.php add_payment_info
Step 3: Confirmation checkout_confirmation.php add_shipping_info
Step 4: Success checkout_success.php purchase

🔧 Step 2: Inject dataLayer.push() on Each Page

Step 1begin_checkout in checkout_shipping.php

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  event: "begin_checkout",
  ecommerce: {
    currency: "USD",
    items: <?= json_encode($cart_items_array); ?>
  }
});
</script>

Step 2 add_payment_info in checkout_payment.php

<script>
dataLayer.push({
event: "add_payment_info",
ecommerce: {
items: <?= json_encode($cart_items_array); ?>,
payment_type: "Credit Card"
}
});
</script>

Step 3add_shipping_info in checkout_confirmation.php

<script>
dataLayer.push({
  event: "add_shipping_info",
  ecommerce: {
    items: <?= json_encode($cart_items_array); ?>,
    shipping_tier: "Standard"
  }
});
</script>

Step 4 purchase in checkout_success.php

<script>
dataLayer.push({
  event: "purchase",
  ecommerce: {
    transaction_id: "<?= $order['id']; ?>",
    value: <?= $order['total']; ?>,
    currency: "USD",
    items: <?= json_encode($order['products']); ?>
  }
});
</script>

🏷️ Step 3: Create GA4 Event Tags in GTM

For each checkout step:

1. GA4 Event Tag: begin_checkout

  • Tag type: GA4 Event
  • Configuration Tag: Your GA4 config
  • Event name: begin_checkout
  • Event parameters:
    • items{{DL - ecommerce.items}}
    • currency{{DL - ecommerce.currency}}

Trigger: Custom Event = begin_checkout

2. GA4 Event Tag: add_payment_info

  • Event name: add_payment_info
  • Add parameter payment_type if available

Trigger: Custom Event = add_payment_info

3. GA4 Event Tag: add_shipping_info

  • Event name: add_shipping_info
  • Parameter shipping_tier = {{DL - ecommerce.shipping_tier}}

Trigger: Custom Event = add_shipping_info

4. GA4 Event Tag: purchase

  • Event name: purchase
  • Parameters: transaction_id, value, currency, items

Trigger: Custom Event = purchase

✅ Step 4: Test in Preview & GA4 DebugView

  1. Enable GTM Preview Mode
  2. Navigate through the checkout pages
  3. On each page:
    • Ensure correct event is pushed
    • GTM Tag fires as expected

In GA4 → Admin → DebugView, confirm that events are hitting with data

📈 Step 5: Create a Funnel Exploration Report in GA4

  1. Go to GA4 → Explore → Funnel Exploration
  2. Add Funnel Steps:
    • Step 1: begin_checkout
    • Step 2: add_payment_info
    • Step 3: add_shipping_info
    • Step 4: purchase
  3. Choose Breakdown Dimensions:
    • device_category
    • session_source/medium
    • item_category
  4. Enable open funnel to track where users drop off

📊 Example Funnel Insights You Can Derive

Insight Action
High drop-off after shipping → payment Simplify payment methods or fix errors
Drop after payment → confirmation Show trust badges, reduce field friction
High mobile abandonment Optimize form UX for mobile
Segment-based drop-offs Adjust targeting in PPC/SEO campaigns

🧠 Bonus: Trigger Scroll or Field Abandon Events

To capture early exits:

window.addEventListener("beforeunload", function() {
  if (window.location.pathname.includes("checkout")) {
    dataLayer.push({
      event: "checkout_abandon",
      step: window.location.pathname
    });
  }
});

Set up a GA4 Event Tag checkout_abandon to measure hard exits.

🧾 Summary

You now have a complete GA4-based checkout drop-off tracking system for osCommerce:

  • All major checkout steps tracked with ecommerce events
  • Events pushed from the server dynamically
  • GA4 tags fire based on real user actions
  • Funnel visualized in GA4 with custom drop-off insights

🔄 What’s Next?

  • Connect Google Ads audience to re-engage abandoners
  • A/B test checkout steps using VWO or Google Optimize
  • Send checkout step info server-side via GTM SS for better attribution

Facebook Ads Enhanced Conversion Tracking Strategy in OpenCart (Web + Server-Side GTM)

Standard

Enhanced Conversions for Facebook Ads is essential in today’s privacy-constrained ad environment. By sending hashed first-party data (email, phone, name) alongside your conversions, you dramatically improve match rates and campaign performance—even with limited browser-based tracking.

🧰 Prerequisites

Item Requirement
Facebook Pixel & CAPI Access From Facebook Events Manager
OpenCart 3.x / 4.x With theme & controller access
Web + Server GTM Installed GTM snippet in OpenCart header
HTTPS Active For privacy compliance
Consent Mode (Optional) For GDPR/CCPA use cases


🔍 What Are Enhanced Conversions?

Enhanced conversions send hashed customer data (e.g. email, phone) alongside the purchase event to Facebook—either via Pixel or CAPI. This helps Facebook match the event to real users, even if cookies are blocked.

✅ We’ll implement both Web Pixel and Server-Side CAPI for reliable deduplication.


🛒 Step 1: Capture Purchase + Customer Data in OpenCart

Edit: catalog/controller/checkout/success.php

Add this PHP logic:

$order_id = $this->session->data['order_id'];
$order_info = $this->model_checkout_order->getOrder($order_id);
$products = $this->model_checkout_order->getOrderProducts($order_id);

$email = strtolower(trim($order_info['email']));
$phone = preg_replace('/\D/', '', $order_info['telephone']);

$items = [];
foreach ($products as $product) {
$items[] = [
'id' => $product['model'],
'name' => $product['name'],
'quantity' => $product['quantity'],
'price' => $product['price']
];
}

$data['fb_enhanced'] = json_encode([
'event' => 'fb_purchase',
'email' => hash('sha256', $email),
'phone' => hash('sha256', $phone),
'value' => $order_info['total'],
'currency' => $order_info['currency_code'],
'transaction_id' => $order_info['order_id'],
'content_ids' => array_column($items, 'id'),
'content_type' => 'product',
'event_id' => uniqid('fb_', true)
]);


📦 Step 2: Push Data to Web GTM on Success Page

Edit: catalog/view/theme/*/template/checkout/success.twig

{% if fb_enhanced %}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ fb_enhanced|raw }});
</script>
{% endif %}

✅ Now GTM has access to all hashed user data + transaction ID.


🎯 Step 3: Setup Facebook Pixel with Enhanced Conversions (Web GTM)

  1. Go to GTM → New Tag → Custom HTML
  2. Use the following code for the Purchase Event:

<script>
fbq('track', 'Purchase', {
value: {{DL - value}},
currency: '{{DL - currency}}',
content_ids: {{DL - content_ids}},
content_type: 'product'
}, {
eventID: '{{DL - event_id}}'
});

fbq('init', 'YOUR_PIXEL_ID', {
em: '{{DL - email}}',
ph: '{{DL - phone}}'
});
</script>

Trigger: Custom Event = fb_purchase

✅ This sends both purchase and enhanced data to Meta.


🛰️ Step 4: Forward to Server-Side GTM (Optional)

To strengthen tracking even further, forward this data to your Server GTM container:

<script>
fetch('https://gtm.yoursite.com/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event_name: 'Purchase',
event_id: '{{DL - event_id}}',
email: '{{DL - email}}',
phone: '{{DL - phone}}',
value: '{{DL - value}}',
currency: '{{DL - currency}}',
transaction_id: '{{DL - transaction_id}}',
content_ids: {{DL - content_ids}},
content_type: 'product',
action_source: 'website'
})
});
</script>


🌐 Step 5: Configure Facebook CAPI Tag in Server-Side GTM

  1. Use the Facebook Conversions API Template
  2. Tag Settings:

Field Value
Pixel ID YOUR_PIXEL_ID
Access Token From Meta Events Manager
Event Name Purchase
Event ID {{event_id}}
Email {{email}}
Phone {{phone}}
Value {{value}}
Currency {{currency}}
Content IDs {{content_ids}}
Transaction ID {{transaction_id}}
Action Source website

  1. Trigger: Event Name equals Purchase


🔁 Step 6: Deduplicate Client & Server Events

To avoid duplicate events in Meta:

  • Use identical event_id for both Pixel and CAPI
  • Meta will deduplicate automatically


🧪 Step 7: QA and Testing

Tool Purpose
Facebook Test Events Tool Debug CAPI/Pixels
Server GTM Preview Mode Verify request payload
Chrome DevTools → Network Check event firing
Meta Events Manager Review deduplication success


✅ Tips for Optimization

Tip Benefit
SHA256 hash in PHP More secure than client-side hashing
Use event_id for deduplication Accurate reporting
Add fbc and fbp cookies in fetch payload Further matching accuracy
Implement consent checks if needed Compliant with GDPR/CCPA


📊 Performance Impact

Metric Before EC After EC
Match Rate ~40–60% 80–95%
Conversion Accuracy Low (cookies only) High (cookies + hashed PII)
Attribution Lag Higher Lower
Retargeting Unreliable More precise


📦 Architecture Overview

[OpenCart Checkout Success]

[dataLayer Push → GTM Web]
↓ ↘
[Pixel with EC] [Forwarded to ssGTM]

[Facebook Conversions API]


Setting Up Pinterest Conversion API for OpenCart with Product Catalog Events

Standard

As cookies continue to degrade and tracking accuracy drops, Pinterest’s Conversion API (CAPI) is now crucial for eCommerce advertisers. By combining server-side tracking with product catalog events, you can significantly improve Pinterest’s ability to match users, attribute sales, and optimize campaigns for ROAS.

🧰 Prerequisites

Requirement Notes
OpenCart (v3.x or v4.x) With template access
Pinterest Tag ID From Pinterest Ads Manager
Pinterest CAPI Access Token From Ads Manager (CAPI setup)
GTM Web + Server Containers Installed and deployed
Product Feed Catalog Synced via Pinterest Business Manager


🎯 What You’ll Track

Event Purpose
PageVisit Product pageview
AddToCart Intent event
Checkout (Purchase) Conversion + value
Product ID Synced with Catalog Feed (via model in OpenCart)


🗂️ Implementation Plan

OpenCart Pages → Web GTM Pushes Event → Server GTM Receives + Sends to Pinterest CAPI


🔹 Step 1: Generate Pinterest Access Token

  1. Go to Pinterest Ads Manager → Conversions → API Access
  2. Create a new CAPI token
  3. Save:
    • Pinterest Tag ID (e.g., 2612238051234)
    • Access Token


🔹 Step 2: Setup DataLayer Push on Product Page

Edit: catalog/view/theme/*/template/product/product.twig

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'pinterest_view_item',
product_id: '{{ product.model }}',
product_name: '{{ product.name|escape('js') }}',
value: '{{ product.price }}',
currency: '{{ session.currency }}',
event_id: 'pin_{{ product.product_id }}_{{ microtime(true) | round(0, 'common') }}'
});
</script>


🔹 Step 3: Track AddToCart on AJAX Cart Add (Optional Enhancement)

Update the controller handling add to cart (usually catalog/controller/checkout/cart.php) to also respond with a DataLayer-friendly payload (or track via MutationObserver if it’s client-side JS).

For simplicity, let’s inject on product pages using a click listener in Web GTM.


🔹 Step 4: Track Purchase on Success Page

In catalog/controller/checkout/success.php:

$order_id = $this->session->data['order_id'];
$order_info = $this->model_checkout_order->getOrder($order_id);
$products = $this->model_checkout_order->getOrderProducts($order_id);

$items = [];
foreach ($products as $p) {
$items[] = $p['model'];
}

$email = strtolower(trim($order_info['email']));
$phone = preg_replace('/\D/', '', $order_info['telephone']);

$data['pinterest_purchase'] = json_encode([
'event' => 'pinterest_purchase',
'product_ids' => $items,
'value' => $order_info['total'],
'currency' => $order_info['currency_code'],
'email' => hash('sha256', $email),
'phone' => hash('sha256', $phone),
'event_id' => uniqid('pin_purchase_', true)
]);

In success.twig:

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ pinterest_purchase|raw }});
</script>


🔹 Step 5: Web GTM – Set Up Triggers

Trigger 1: pinterest_view_item
Trigger 2: pinterest_add_to_cart
Trigger 3: pinterest_purchase

✅ Each trigger sends an event to the Server GTM endpoint (e.g., via fetch or GA4 transport)

Optional JS Fetch Forwarding:

fetch('https://gtm.yoursite.com/event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event_name: '{{DL - event}}',
product_ids: {{DL - product_ids}},
value: '{{DL - value}}',
currency: '{{DL - currency}}',
email: '{{DL - email}}',
phone: '{{DL - phone}}',
event_id: '{{DL - event_id}}',
action_source: 'website'
})
});


🔹 Step 6: Setup Pinterest CAPI in Server-Side GTM

  1. Import or create a Pinterest Conversion API Tag (use custom HTTP request tag or template)
  2. Request URL:
    https://api.pinterest.com/v5/events
  3. Payload Example:

{
"event_name": "checkout",
"event_time": {{Timestamp}},
"event_id": "{{event_id}}",
"action_source": "website",
"user_data": {
"em": "{{email}}",
"ph": "{{phone}}"
},
"custom_data": {
"currency": "{{currency}}",
"value": {{value}},
"content_ids": {{product_ids}},
"content_type": "product"
}
}

  1. Header Setup:

Header Value
Authorization Bearer YOUR_ACCESS_TOKEN
Content-Type application/json

  1. Trigger: Custom Trigger for each event name:
    • Event equals pinterest_purchase
    • Event equals pinterest_view_item
    • Event equals pinterest_add_to_cart


🔹 Step 7: Ensure Deduplication

  • Send unique event_id in both pixel and CAPI (if you also implement client pixel)
  • Pinterest automatically deduplicates based on event_id


🧪 QA & Debugging

Tool Use
Server GTM Preview Verify event data and API response
Pinterest Event Manager Confirm CAPI events
Chrome → DevTools → Network Validate fetch or pixel delivery
Pinterest Tag Helper Extension Debug client-side tags


🔐 Bonus: Set Cookie for epik (Pinterest Click ID)

In header.twig:

<script>
const epik = new URLSearchParams(window.location.search).get('epik');
if (epik) {
document.cookie = `epik=${epik}; path=/; max-age=2592000; SameSite=Lax`;
}
</script>

✅ You can later read this cookie in Server GTM via event.data.cookie.epik.


📦 Architecture Overview

[OpenCart Product or Success Page]

[dataLayer Push (Web GTM)]
↓ ↘
[Pixel (optional)] [Fetch → Server GTM]

[Pinterest CAPI]


🔄 Snapchat Pixel + CAPI Implementation for OpenCart Product Sales (Web + Server-Side GTM)

Standard

Snapchat is a rapidly growing ad platform for eCommerce, especially among younger audiences. To track sales performance accurately and combat ad blockers and iOS restrictions, implementing both the Snapchat Pixel and Conversions API (CAPI) is essential.

🧰 Prerequisites

Requirement Notes
OpenCart 3.x or 4.x Template and backend access
Web GTM Installed Add via header.twig
Server-Side GTM Setup Use custom domain like gtm.yoursite.com
Snapchat Pixel ID & CAPI Token Get from Snap Ads Manager
Consent Banner (optional) For GDPR/CCPA compliance


🗂️ Tracking Plan

Tracked Events:

  • Purchase (Complete Checkout)

Methods:

  • Client-side Pixel → via GTM
  • Server-side CAPI → via Server GTM

User Identifiers:

  • Hashed email & phone
  • IP address & User-Agent (automatically captured)


🔹 Step 1: Create Snapchat Pixel & Access Token

  1. Go to Snapchat Ads Manager
  2. Navigate to Events Manager
  3. Select Web Events > Create Pixel
  4. Generate API Token under “Conversions API Settings”

Save:

  • Pixel ID (e.g., 0a12b3c4-5678-9def-1234-567890abcde1)
  • Access Token


🔹 Step 2: Capture Purchase Data in OpenCart

Edit: catalog/controller/checkout/success.php

$order_id = $this->session->data['order_id'];
$order_info = $this->model_checkout_order->getOrder($order_id);
$products = $this->model_checkout_order->getOrderProducts($order_id);

$items = [];
foreach ($products as $product) {
$items[] = [
'item_id' => $product['model'],
'item_name' => $product['name'],
'quantity' => $product['quantity'],
'price' => $product['price']
];
}

$email = strtolower(trim($order_info['email']));
$phone = preg_replace('/\D/', '', $order_info['telephone']);

$data['snap_event_data'] = json_encode([
'event' => 'snap_purchase',
'transaction_id' => $order_id,
'value' => $order_info['total'],
'currency' => $order_info['currency_code'],
'content_ids' => array_column($items, 'item_id'),
'email' => hash('sha256', $email),
'phone' => hash('sha256', $phone),
'event_id' => uniqid('snap_', true)
]);


🔹 Step 3: Inject dataLayer Push in success.twig

{% if snap_event_data %}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ snap_event_data|raw }});
</script>
{% endif %}

✅ Now Web GTM can access purchase data and user identifiers.


🔹 Step 4: Configure Snapchat Pixel Tag in Web GTM

Use the Snap Pixel template from GTM Gallery:

  1. Tag Type: Snap Pixel
  2. Event Type: PURCHASE
  3. Pixel ID: Your Pixel ID
  4. Add parameters:
    • transaction_id: {{DL - transaction_id}}
    • value, currency, content_ids
    • event_id: {{DL - event_id}} (for deduplication)

Trigger: Custom Event equals snap_purchase


🔹 Step 5: Forward Event to Server-Side GTM

Add a fetch() call in the same tag (or create a separate tag):

<script>
fetch("https://gtm.yoursite.com/event", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
event_name: "PURCHASE",
transaction_id: '{{DL - transaction_id}}',
currency: '{{DL - currency}}',
value: '{{DL - value}}',
content_ids: {{DL - content_ids}},
event_id: '{{DL - event_id}}',
email: '{{DL - email}}',
phone: '{{DL - phone}}',
action_source: "website"
})
});
</script>

✅ This forwards to the Server-Side GTM endpoint for server delivery to Snap.


🔹 Step 6: Configure Snapchat CAPI in Server-Side GTM

  1. Import the Snapchat CAPI Tag Template
  2. Fill in:

Field Value
Pixel ID Your Snap Pixel ID
Access Token From Snapchat
Event Type PURCHASE
Event ID {{event_id}}
Value {{value}}
Currency {{currency}}
Content IDs {{content_ids}}
Email {{email}}
Phone {{phone}}
Transaction ID {{transaction_id}}
Action Source website

Trigger: Event Name equals PURCHASE


🔹 Step 7: Deduplication

Snapchat uses event_id to deduplicate client + server events.

Ensure:

  • Pixel and CAPI both include the same event_id
  • Event IDs are unique per transaction and match on both ends


🧪 QA Tools & Debugging

Tool Use
Server GTM → Preview Inspect CAPI delivery
Chrome DevTools Verify pixel & fetch()
Snapchat Events Manager See “Received via API”
Postman (optional) Test direct API if needed


🧠 Pro Tips

Tip Reason
Hash email/phone in backend Avoid exposing raw PII
Add snapclid cookie Useful for future attribution matching
Log server response Check for API errors from Snap
Include consent signal To comply with privacy laws


📦 Architecture Summary

[OpenCart Success Page]

[dataLayer → Web GTM]
↓ ↘
[Snap Pixel] [Fetch → Server GTM]

[Snapchat CAPI]


🎯 OpenCart TikTok Conversion API (CAPI) Server-Side Tracking Using GTM

Standard

TikTok is a powerful traffic and conversion channel, especially for Gen Z and Millennial-focused brands. But with ad blockers, browser limitations, and cookie restrictions, client-side tracking using only the TikTok Pixel isn’t enough. That’s where TikTok’s Events API (CAPI) comes in—powered by Server-Side Google Tag Manager (ssGTM).

🧰 Prerequisites

Requirement Notes
OpenCart (v3.x/v4.x) Full template & backend access
TikTok Pixel & Access Token From TikTok Ads Manager
Web + Server GTM Containers Linked to OpenCart & hosted server-side
Consent System (optional) For GDPR/CCPA regions


🗂️ Overview

We’ll implement server-side Purchase tracking like this:

[OpenCart Success Page]

[Web GTM Pushes event_id + dataLayer]

[Server GTM Receives + Forwards to TikTok CAPI]

[TikTok Ads Manager Receives conversion event]


🔹 Step 1: Get TikTok Pixel ID and Access Token

  1. Go to TikTok Ads Manager → Assets → Event Manager
  2. Create/Select Web Event → Copy:
    • Pixel ID (e.g. C93F99XX)
    • Access Token (long secure token for CAPI)


🔹 Step 2: Capture Conversion Data on OpenCart Success Page

Edit file: catalog/controller/checkout/success.php

Add:

$order_id = $this->session->data['order_id'];
$order_info = $this->model_checkout_order->getOrder($order_id);
$products = $this->model_checkout_order->getOrderProducts($order_id);

$items = [];
foreach ($products as $product) {
$items[] = [
'content_id' => $product['model'],
'content_name' => $product['name'],
'quantity' => $product['quantity'],
'price' => $product['price']
];
}

$email = strtolower(trim($order_info['email']));
$phone = preg_replace('/\D/', '', $order_info['telephone']);

$event_payload = [
'event' => 'tt_purchase',
'value' => $order_info['total'],
'currency' => $order_info['currency_code'],
'content_type' => 'product',
'content_ids' => array_column($items, 'content_id'),
'email' => hash('sha256', $email),
'phone' => hash('sha256', $phone),
'event_id' => uniqid('tt_', true)
];

$data['tt_event_data'] = json_encode($event_payload);


🔹 Step 3: Push Data to GTM in success.twig

In catalog/view/theme/*/template/checkout/success.twig:

{% if tt_event_data %}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({{ tt_event_data|raw }});
</script>
{% endif %}

✅ This makes the server-safe, hashed event data available in the dataLayer.


🔹 Step 4: Setup TikTok Pixel Tag in Web GTM

  1. Create a Custom HTML Tag:

<script>
ttq.track('CompletePayment', {
value: {{DL - value}},
currency: '{{DL - currency}}',
contents: {{DL - content_ids}},
content_type: 'product'
}, {event_id: '{{DL - event_id}}'});
</script>

  1. Trigger: Event equals tt_purchase

✅ This fires the Pixel + event_id for deduplication.


🔹 Step 5: Forward Event to Server GTM (Optional but Best Practice)

In the same tag, use fetch() or GA4 transport_url method:

<script>
fetch("https://gtm.yoursite.com/event", {
method: "POST",
body: JSON.stringify({
event_name: "tt_purchase",
email: '{{DL - email}}',
phone: '{{DL - phone}}',
value: '{{DL - value}}',
currency: '{{DL - currency}}',
event_id: '{{DL - event_id}}',
content_ids: {{DL - content_ids}}
}),
headers: { "Content-Type": "application/json" }
});
</script>


🔹 Step 6: Setup TikTok CAPI Tag in Server GTM

Use the TikTok Events API Tag Template:

  1. Install from GTM Community Template Gallery:
    TikTok CAPI Template
  2. Configure:

Field Value
Pixel ID Your TikTok Pixel ID
Access Token From TikTok Business Manager
Event Name CompletePayment
Event ID {{event_id}}
Currency {{currency}}
Value {{value}}
Hashed Email {{email}}
Hashed Phone {{phone}}
Content IDs {{content_ids}}

Trigger: Event Name equals tt_purchase

✅ This ensures the event is reliably sent to TikTok even if Pixel is blocked.


🔹 Step 7: Deduplicate Pixel + CAPI

Make sure:

  • event_id is identical for both Pixel and Server event
  • Meta Events Manager shows “Matched” and “Deduplicated”


🔹 Step 8: Validate Setup

Tool Use
TikTok Events Test Tool Validate CAPI delivery
Server GTM Preview Check incoming JSON
Chrome DevTools → Network Check Pixel delivery
TikTok Ads Manager Monitor conversions and deduplication


🧠 Bonus: Add TikTok Click ID (ttclid) to Cookie

Add to header.twig:

<script>
const ttclid = new URLSearchParams(window.location.search).get('ttclid');
if (ttclid) {
document.cookie = `ttclid=${ttclid}; path=/; max-age=2592000; SameSite=Lax`;
}
</script>

✅ Use this ttclid in Server GTM to tie ad clicks to conversions.


📦 Summary Architecture

[OpenCart Success Page]

[dataLayer → Web GTM Pixel + Forward to ssGTM]
↓ ↓
[Client Pixel] [Server-Side GTM]

[TikTok Events API]


🔁 Facebook Pixel + Conversions API (CAPI) Setup in OpenCart via GTM (Web + Server-Side)

Standard

Tracking performance on Meta (Facebook/Instagram) is increasingly dependent on server-side implementation. Browser-based Pixel tracking alone is no longer reliable due to iOS 17 privacy protections, ad blockers, and limited cookie lifespans.

🎯 Goals

  • Full-funnel event tracking for Meta (PageView, ViewContent, AddToCart, Purchase)
  • Deduplicated server + client event tracking
  • Resilient tracking even when cookies are blocked
  • Hashed email/phone support for audience matching


🧰 Prerequisites

Requirement Notes
OpenCart (v3.x or v4.x) Full template + backend access
Web GTM installed Use header.twig
Server-Side GTM container deployed Prefer custom domain like gtm.yoursite.com
Meta Pixel ID From Events Manager
Meta Access Token From Business Settings > CAPI Setup


🚀 Step-by-Step Implementation


🔹 Step 1: Create Meta Pixel and Access Token

  1. Go to Meta Events Manager
  2. Create or select a Pixel
  3. Generate Access Token (under Conversions API Settings)
  4. Note:
    • Pixel ID: 123456789012345
    • Access Token: EAABsb...


🔹 Step 2: Setup Web GTM – Facebook Pixel Tags

In header.twig, add GTM snippet:

<!-- 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 -->

✅ Use this for standard GTM pixel injection.


🔹 Step 3: Push DataLayer Events in OpenCart

In product.twig (ViewContent):

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'fb_view_content',
content_ids: ['{{ product.model }}'],
content_type: 'product',
value: '{{ product.price }}',
currency: '{{ session.currency }}',
content_name: '{{ product.name|escape("js") }}'
});
</script>

In success.twig (Purchase):

<script>
dataLayer.push({
event: 'fb_purchase',
value: '{{ total }}',
currency: '{{ currency }}',
content_ids: [{% for p in products %}'{{ p.model }}'{% if not loop.last %},{% endif %}{% endfor %}],
content_type: 'product',
email: '{{ customer.email|lower|sha256 }}',
phone: '{{ customer.telephone|sha256 }}',
event_id: 'fbp_{{ order_id }}'
});
</script>

✅ Hash email and phone in PHP using SHA256 before injecting into Twig.


🔹 Step 4: Setup Facebook Pixel Tags in Web GTM

Use Custom HTML Tags or Facebook Pixel Tag Template (preferred):

  1. ViewContent Tag
    • Trigger: fb_view_content
    • Payload:

fbq('track', 'ViewContent', {
content_ids: {{DL - content_ids}},
content_type: 'product',
value: {{DL - value}},
currency: {{DL - currency}}
}, {eventID: {{DL - event_id}} });

  1. Purchase Tag
    • Trigger: fb_purchase
    • Same structure, track('Purchase', {...})

✅ Ensure each client event passes a unique event_id


🔹 Step 5: Setup Forwarding to Server-Side GTM

In the same event tag (Purchase), forward to ssGTM via transport_url using GA4 or custom Fetch:

If using Custom HTTP Request Tag:

fetch("https://gtm.yoursite.com/event", {
method: "POST",
body: JSON.stringify({
event_name: "Purchase",
content_ids: {{DL - content_ids}},
value: {{DL - value}},
currency: {{DL - currency}},
event_id: {{DL - event_id}},
email: {{DL - email}},
phone: {{DL - phone}},
action_source: "website"
}),
headers: {
"Content-Type": "application/json"
}
});

✅ Or, send via GA4 tag and use Server GTM to proxy to Meta CAPI.


🔹 Step 6: Server GTM – Set Up Meta CAPI Tag

  1. Use Meta CAPI Tag Template
    Link: Meta Tag in GTM Gallery
  2. Fill Fields:
    • Pixel ID: 123456789012345
    • Access Token: From Meta
    • Event Name: {{Event Data → event_name}}
    • event_id: {{event_id}}
    • email: {{email}}
    • phone: {{phone}}
    • currency/value/content_ids
  3. Trigger: Event Name equals Purchase

✅ You now have full server-side delivery with event deduplication logic.


🔹 Step 7: Deduplicate Server + Client Events

  1. Send event_id in both client (Pixel) and server (CAPI)
  2. In Meta Events Manager, verify:
    • No duplicate
    • CAPI shows as “Processed”
    • Pixel + Server joined under same event


🧪 QA Tools

Tool Purpose
GTM Preview (Web + Server) Debug variables & flow
Meta CAPI Test Events Test server delivery
Meta Events Manager → Diagnostics Check deduplication
Chrome DevTools → Network tab Verify Pixel/Fetch requests


🧠 Pro Tips

Tip Why It Helps
Use custom domain for ssGTM Avoids ad blockers
Pass consent flags if needed GDPR/CCPA compliance
Hash PII server-side Avoid exposing raw data
Enable automatic advanced matching Fallback for missed PII
Log server errors to GCP or webhook Improves reliability


📦 Summary Architecture

[OpenCart Frontend]

[dataLayer → Web GTM]
↓ ↘
[Meta Pixel Tag] [Fetch to ssGTM]

[Server-Side GTM Container]

[Meta Conversions API]