πŸ“Š GA4 Purchase Funnel Analysis for osCommerce CRO (Advanced Setup + Code)

Standard

Understanding where users drop off in your osCommerce store’s purchase journey is critical for Conversion Rate Optimization (CRO). GA4’s Exploration reports and enhanced ecommerce eventsβ€”when combined strategically via Google Tag Managerβ€”can provide powerful, actionable funnel insights.

In this article, you’ll learn how to implement Purchase Funnel Tracking and perform in-depth GA4 funnel analysis tailored for osCommerce.

🧰 Prerequisites

  • Google Tag Manager installed on osCommerce
  • GA4 Configuration Tag already published
  • Enhanced Ecommerce Events implemented (view_item, add_to_cart, begin_checkout, purchase)
  • Access to checkout_success.php and other relevant templates

🎯 Goals of Funnel Analysis

  • Identify drop-offs from product view β†’ add to cart β†’ checkout β†’ purchase
  • Segment funnels by device, product category, source/medium
  • Attribute purchase values accurately
  • Improve CRO through data-backed insights

πŸ›’ Step 1: Define GA4 Funnel Events for osCommerce

Funnel Step GA4 Event Triggered On
Product View view_item Product detail page
Add to Cart add_to_cart Add to cart click
View Cart view_cart Cart page load
Begin Checkout begin_checkout Checkout page load (Step 1)
Add Shipping Info add_shipping_info Shipping page or step 2
Purchase purchase Order success / thank-you page

🧠 Step 2: Data Layer Push on Key Pages in osCommerce

Product Page β†’view_item

In product_info.php:

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  event: "view_item",
  ecommerce: {
    currency: "USD",
    value: <?= $product['price'] ?>,
    items: [{
      item_id: "<?= $product['model'] ?>",
      item_name: "<?= $product['name'] ?>",
      item_category: "<?= $product['category'] ?>",
      price: <?= $product['price'] ?>,
      quantity: 1
    }]
  }
});
</script>

Add to Cart β†’ add_to_cart

In your β€œAdd to Cart” button (usually in product_info.php or JS handler):

<button class="btn btn-primary add-to-cart-btn" 
  data-id="<?= $product['model'] ?>"
  data-name="<?= $product['name'] ?>"
  data-price="<?= $product['price'] ?>"
  onclick="addToCartGTM(this)">
  Add to Cart
</button>

<script>
function addToCartGTM(elem) {
  window.dataLayer = window.dataLayer || [];
  dataLayer.push({
    event: "add_to_cart",
    ecommerce: {
      currency: "USD",
      value: parseFloat(elem.dataset.price),
      items: [{
        item_id: elem.dataset.id,
        item_name: elem.dataset.name,
        price: parseFloat(elem.dataset.price),
        quantity: 1
      }]
    }
  });
}
</script>

Checkout Page β†’ begin_checkout

In checkout_shipping.php or checkout.php:

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

Order Success Page β†’ 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 event (view_item, add_to_cart, begin_checkout, purchase):

  1. Tag Type: GA4 Event
  2. Event Name: Matches GA4’s ecommerce event names
  3. Parameters:
    • value β†’ {{DL - ecommerce.value}}
    • currency β†’ {{DL - ecommerce.currency}}
    • items β†’ {{DL - ecommerce.items}}
  4. Trigger: Custom Event with name matching your event push (e.g. add_to_cart)

βœ… Step 4: Validate Events

Use:

  • GTM Preview Mode to validate triggers
  • GA4 DebugView to check real-time event data
  • Tag Assistant to verify event parameter accuracy

πŸ“ˆ Step 5: Create Funnel Exploration Report in GA4

  1. Go to GA4 β†’ Explore β†’ Funnel Exploration
  2. Steps:
    • view_item
    • add_to_cart
    • begin_checkout
    • purchase
  3. Use custom dimensions (e.g., item_category, device_category, or source/medium)
  4. Filter to only non-bounced sessions for better conversion visibility

πŸ§ͺ Optional Enhancements

Track Intermediate Steps

Add these events for deeper funnel tracking:

  • view_cart (on shopping_cart.php)
  • add_shipping_info (after shipping selection)
  • add_payment_info (after payment selection)

Example:

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

🎯 CRO Tips Based on Funnel Data

Insight Actionable Fix
Low add_to_cart after view_item Improve product copy, images, CTAs
Drop after begin_checkout Simplify checkout forms, reduce steps
Low purchase conversion Enable trust badges, optimize page speed
Mobile drop-offs Improve mobile UX and load time

πŸ“Œ Summary

You now have a fully customized GA4 purchase funnel for osCommerce using GTM:

  • Cleanly structured Enhanced Ecommerce events
  • GA4 Funnel Exploration reports
  • In-depth drop-off analysis
  • Actionable CRO insights

πŸ”„ What’s Next?

  • Integrate server-side GTM for enhanced attribution
  • Use predictive audiences in GA4 to retarget abandoners
  • Combine funnel insights with A/B testing tools like VWO or Google Optimize (if re-enabled)

🎯 Custom Event Tracking in osCommerce with GA4 and GTM (Step-by-Step Guide)

Standard

Custom event tracking in GA4 enables you to measure unique user interactions tailored to your osCommerce storeβ€”such as CTA clicks, form submissions, scroll depth, video plays, or custom button engagements.

In this guide, you’ll learn how to implement fully customized GA4 event tracking in osCommerce via Google Tag Manager.

🧰 Prerequisites

  • βœ… Google Tag Manager installed across all osCommerce pages
  • βœ… GA4 Configuration Tag created in GTM
  • βœ… Access to osCommerce PHP/HTML templates
  • βœ… Developer console or FTP for editing theme files

πŸ“Œ Common Use Cases for Custom Events in osCommerce

Event Name Triggered On
cta_click Click on “Register”, “Buy Now”, or banners
form_submit Lead form or newsletter submission
scroll_80_percent When user scrolls 80% of product page
chat_initiated When user opens live chat
wishlist_add When product is added to wishlist

πŸ”§ Step 1: Plan Your Custom Events

Define the naming convention and parameters in a tracking plan.

Example: cta_click

Parameter Value Example
link_text “Register Now”
page_path “/product_info.php?products_id=12”
cta_type “Top Banner”

πŸ–₯️ Step 2: Add data-attributes or Custom Class to HTML

Modify CTA buttons in osCommerce to include a unique selector.

Example: In includes/modules/content/index/cm_index_products.php

<a href="register.php" class="btn btn-primary custom-cta" 
   data-cta-type="Top Banner" data-cta-text="Register Now">
   Register Now
</a>

🧠 Step 3: Create GTM Click Trigger for Custom CTA

  1. Go to GTM β†’ Triggers β†’ New
  2. Name: Click - CTA Button
  3. Type: Click – All Elements
  4. Trigger Conditions:
    • Click Classes β†’ contains custom-cta

πŸ” Step 4: Create Data Layer Push (optional for more control)

For dynamic events or JS-triggered actions, inject a dataLayer.push() using PHP or JavaScript:

Example for JS-triggered event:

<a href="register.php" onclick="dataLayer.push({
  event: 'cta_click',
  link_text: 'Register Now',
  cta_type: 'Top Banner',
  page_path: window.location.pathname
})" class="btn btn-primary">Register Now</a>

🏷️ Step 5: Create GA4 Event Tag in GTM

  1. Go to Tags β†’ New
  2. Choose: GA4 Event
  3. Configuration Tag: Select your GA4 config
  4. Event Name: cta_click
  5. Event Parameters:
    • link_text β†’ {{Click Text}}
    • cta_type β†’ {{Click Element - CTA Type}}
    • page_path β†’ {{Page Path}}

πŸ§ͺ Step 6: Define Custom Variables in GTM

  1. Click Element – CTA Type
    • Type: DOM Element
    • Selector: Click Element
    • Attribute name: data-cta-type
  2. Click Text
    • Built-in Variable β†’ Enable Click Text

πŸ§ͺ Step 7: Test in GTM Preview and GA4 DebugView

  1. Enable GTM Preview Mode
  2. Navigate to a page with the CTA
  3. Click the button and ensure:
    • The custom event triggers in GTM
    • Event appears in GA4 DebugView

πŸ” Step 8: View in GA4 Reports

Go to:

GA4 β†’ Reports β†’ Engagement β†’ Events

You will see your event name cta_click. You can also create custom exploration reports or audiences using these parameters.

βž• Bonus: Track Scroll Depth or Other UX Events

Scroll Event Example using GTM Trigger:

  1. Trigger type: Scroll Depth
  2. Vertical Scroll Depths: 80
  3. Fire once per page

Then tag with:

  • Event name: scroll_80_percent
  • Parameters: page_title, page_path

πŸ“Œ Summary of Custom Event Implementation

Step Action
1 Add unique HTML attributes or use JS for events
2 Use dataLayer.push() or click triggers in GTM
3 Create GA4 Event Tags mapped to your custom data
4 Test in GTM Preview and GA4 DebugView
5 Report & optimize based on custom engagement data

βœ… Best Practices

  • Follow GA4 naming conventions: lowercase, snake_case
  • Use GTM Variables to dynamically pass values
  • Combine with Enhanced Ecommerce for deeper funnel analysis
  • Add triggers like form submit, video start, or live chat open

πŸš€ Final Thoughts

Custom event tracking in osCommerce using GTM and GA4 enables precise behavioral insights that go beyond standard ecommerce metrics. Whether you’re optimizing CTAs, forms, or scroll depth, these events become essential signals for conversion rate optimization, remarketing, and product strategy.

Want to go further? Add these events to your server-side GTM container for durable attribution!

 

πŸ” GA4 Enhanced Ecommerce Setup in osCommerce via GTM (Step-by-Step Guide)

Standard

Enhanced Ecommerce tracking in Google Analytics 4 (GA4) allows you to track user interactions with products on your osCommerce storeβ€”from impressions to purchases. This article walks you through setting it up via Google Tag Manager (GTM), ensuring a scalable and privacy-compliant data architecture.

βœ… Prerequisites

  • Google Tag Manager installed on all osCommerce pages
  • GA4 Configuration Tag already published
  • Access to osCommerce source code
  • GTM Data Layer strategy document (recommended)

🎯 Goals of Enhanced Ecommerce Setup

  • Track Product Impressions
  • Track Product Clicks
  • Track Product Detail Views
  • Track Add to Cart / Remove from Cart
  • Track Checkout Funnel Steps
  • Track Purchases
  • Optional: Track Refunds

πŸ“¦ Step 1: Define the Data Layer Model for GA4

Use a standardized GA4 Ecommerce schema. Below is a sample structure:

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  event: "view_item",
  ecommerce: {
    currency: "USD",
    value: 49.99,
    items: [{
      item_id: "SKU_12345",
      item_name: "Sample Product",
      item_category: "Shirts",
      item_variant: "Blue",
      item_brand: "BrandX",
      price: 49.99,
      quantity: 1
    }]
  }
});
</script>

Each ecommerce event will require a similar push with modified parameters.

πŸ›οΈ Step 2: Inject Data Layer in osCommerce

You’ll need to modify osCommerce’s PHP templates to inject the dataLayer pushes dynamically.

Example: Inject on Product Page (product_info.php)

<?php
$product = getProductData($product_id); // Replace with actual logic
echo "<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  event: 'view_item',
  ecommerce: {
    currency: 'USD',
    value: {$product['price']},
    items: [{
      item_id: '{$product['model']}',
      item_name: '{$product['name']}',
      item_category: '{$product['category']}',
      item_variant: '{$product['color']}',
      item_brand: '{$product['brand']}',
      price: {$product['price']},
      quantity: 1
    }]
  }
});
</script>";
?>

Repeat similarly for:

  • Category Pages (product impressions)
  • Cart Page
  • Checkout Steps
  • Order Success Page

🧠 Step 3: Setup GA4 Ecommerce Tags in GTM

πŸ”Ή Create a GA4 Event Tag for Each Ecommerce Event

Go to GTM β†’ Tags β†’ New β†’ GA4 Event Tag

Choose your GA4 Configuration Tag

Set the event name, e.g., view_item, add_to_cart, purchase

In “Event Parameters”, add:

  • items β†’ {{DL - ecommerce.items}} (Custom Variable)
  • currency β†’ {{DL - ecommerce.currency}}
  • value β†’ {{DL - ecommerce.value}} (only for purchase, view_item, etc.)

Sample Mapping:

GA4 Event Name Trigger Location DataLayer Event
view_item Product Detail Page view_item
add_to_cart Add to Cart Button Click add_to_cart
remove_from_cart Remove Button Click remove_from_cart
view_cart Cart Page view_cart
begin_checkout Checkout Start begin_checkout
purchase Order Success Page purchase

 

πŸ”§ Step 4: Create Triggers for Each Event

Example: Trigger for view_item

  • Type: Custom Event
  • Event name: view_item

Repeat for add_to_cart, purchase, etc.

🧩 Step 5: Optional – Custom JS Variables in GTM

Use Custom JS to extract product list or dynamic values if needed.

function() {
  return window.dataLayer.find(dl => dl.event === 'view_item')?.ecommerce?.items || [];
}

🧾 Step 6: Purchase Event Example in osCommerce

Modify the checkout_success.php to push a purchase event:

<?php
$order = getOrderDetails($order_id);
$items = [];
foreach ($order['products'] as $product) {
  $items[] = [
    'item_id' => $product['model'],
    'item_name' => $product['name'],
    'price' => $product['price'],
    'quantity' => $product['quantity']
  ];
}
echo "<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  event: 'purchase',
  ecommerce: {
    transaction_id: '{$order['id']}',
    currency: 'USD',
    value: {$order['total']},
    items: " . json_encode($items) . "
  }
});
</script>";
?>

βœ… Step 7: Testing with GTM & GA4 DebugView

  1. Enable GTM Preview Mode.
  2. Navigate through your osCommerce store.
  3. Open GA4 β†’ Admin β†’ DebugView.
  4. Verify each ecommerce event with correct parameters.

πŸ›  Optional Enhancements

  • πŸ” Add Refund tracking (refund event on admin panel post refund processing)
  • πŸ”’ Anonymize IP or use Consent Mode for compliance
  • πŸ“Š Create GA4 Exploration Reports for funnel analysis
  • πŸ’° Integrate Server-Side GTM to improve attribution accuracy

πŸ“ˆ Final Thoughts

GA4 Enhanced Ecommerce in osCommerce using GTM delivers powerful, structured insights. With the right data layer setup and GTM tagging strategy, you’ll unlock a full-funnel view of user behavior and conversion pathsβ€”vital for PPC optimization, CRO, and remarketing campaigns.

Ensure regular testing and QA, especially after site or template updates.

 

πŸ”„ Tracking Refunds & Returns Server-Side for Clean ROAS Reporting in OpenCart

Standard

Tracking refunds and returns is just as important as tracking purchasesβ€”especially when you’re optimizing ad spend. Without proper refund tracking, your ROAS (Return on Ad Spend) metrics are inflated, leading to poor optimization in Google Ads, Meta, and GA4.


🎯 Why Refund Tracking Matters

Problem Impact
ROAS inflation Over-reports revenue in Google Ads, Meta, GA4
Misleading attribution Ads get credit even when purchase is reversed
Poor bid optimization Smart Bidding algorithms get incorrect feedback
No refund data in GA4 Incomplete funnel analysis & reporting

βœ… Solution: Trigger refund events from the backend and route them through Server-Side GTM to GA4, Google Ads, and Meta CAPI.


🧰 Prerequisites

  • OpenCart store (v3.x or v4.x)
  • Access to the order return system (Admin β†’ Returns)
  • Server-Side GTM Container deployed (gtm.yoursite.com)
  • Google Ads + GA4 + Meta CAPI setup
  • Consent handling logic (optional but recommended)


πŸš€ Step-by-Step Guide


πŸ”Ή Step 1: Detect Refund Trigger in OpenCart Admin

In OpenCart, refunds typically happen when a return is approved.

Modify the file:
admin/controller/sale/return.php

Find where the return status is updated, and hook into it:

if ($this->request->server['REQUEST_METHOD'] == 'POST' && isset($this->request->post['return_status_id'])) {
$return_id = (int)$this->request->get['return_id'];
$return_status_id = (int)$this->request->post['return_status_id'];

// When return is approved (adjust ID as per your config)
if ($return_status_id == APPROVED_STATUS_ID) {
$this->load->model('sale/return');
$return_info = $this->model_sale_return->getReturn($return_id);

$this->load->model('sale/order');
$order_info = $this->model_sale_order->getOrder($return_info['order_id']);
$products = $this->model_sale_order->getOrderProducts($return_info['order_id']);

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

$refund_event = [
'event_name' => 'refund',
'transaction_id' => $order_info['order_id'],
'currency' => $order_info['currency_code'],
'items' => $items,
'event_id' => uniqid('refund_', true),
'user_data' => [
'email' => hash('sha256', strtolower(trim($order_info['email']))),
'phone' => hash('sha256', preg_replace('/\D/', '', $order_info['telephone']))
]
];

// Send to server-side GTM endpoint
$endpoint = 'https://gtm.yoursite.com/collect';
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($refund_event));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
}


πŸ”Ή Step 2: Receive Refund Data in Server-Side GTM

In your Server GTM container:

  1. Open Preview Mode
  2. Trigger a refund from OpenCart
  3. Check the incoming request β€” event_name should be refund


πŸ”Ή Step 3: Create Variables in Server GTM

  • Event Name: {{Event Data β†’ event_name}}
  • Transaction ID: {{Event Data β†’ transaction_id}}
  • Currency: {{Event Data β†’ currency}}
  • Items: {{Event Data β†’ items}}
  • Event ID: {{Event Data β†’ event_id}}
  • user_data.email, user_data.phone


πŸ”Ή Step 4: Send Refund to GA4 via Server Tag

Create a GA4 Event Tag:

  • Tag Type: Google Analytics: GA4
  • Event Name: refund
  • Transaction ID: {{transaction_id}}
  • Items: {{items}}
  • User Properties (optional): email/phone

Trigger: Event Name equals refund


πŸ”Ή Step 5: Send Refund to Google Ads

In Server GTM:

  1. Create Google Ads Conversion Tag
  2. Use conversion_label, conversion_id
  3. Set value to 0 or refund amount (if partial refund logic is applied)
  4. Add transaction_id and event_id
  5. Trigger: When event_name == refund

βœ… This updates your Google Ads account to reflect the refund, adjusting ROAS.


πŸ”Ή Step 6: Send Refund to Meta via CAPI

Use Meta CAPI HTTP Request Tag:

  • event_name: Refund
  • event_id: {{event_id}}
  • em, ph: email and phone hashes
  • transaction_id, currency, value: if available
  • action_source: website


πŸ”Ή Step 7: Validate and Test

Tool Use
GA4 DebugView Validate refund hits
Server GTM Preview Check payloads
Meta CAPI Test Events Confirm receipt
Google Ads Conversion Troubleshooter Check for adjusted ROAS


🧠 Pro Tips

Tip Why It Helps
Use event_id to deduplicate Prevents same refund from firing multiple times
Log refunds server-side Useful for audits and anomaly detection
Use server response logging Catch failed refund delivery to GTM
Consider partial refund logic Track only refunded item values if needed
Include consent signal if regulated Ensures privacy compliance


πŸ“¦ Summary Flow

[Admin Approves Refund in OpenCart]
↓
[Backend PHP Fires Event to ssGTM]
↓
[Server-Side GTM Container]
↓ ↓ ↓
[GA4] [Google Ads] [Meta CAPI]


πŸ” OpenCart Server-Side Tagging: Capturing Email & Phone as First-Party Data

Standard

In a privacy-first digital world, first-party data such as email and phone number are critical for accurate ad attribution, audience building, and conversion trackingβ€”especially for Meta CAPI, Google Ads Enhanced Conversions, and server-side GA4.

βœ… Why Capture First-Party Identifiers?

Purpose Benefit
Meta CAPI Matching Increases match quality and conversion attribution
Google Ads Enhanced Conversions Helps match conversions to ads without relying on cookies
Cross-device tracking Powers persistent user identity across devices
Compliance You control how and where data flows


🧰 Prerequisites

  • OpenCart v3.x or v4.x with checkout customization access
  • Google Tag Manager Web + Server-Side containers deployed
  • Domain mapped for ssGTM (e.g., gtm.yoursite.com)
  • Basic consent mechanism (CMP or manual logic)
  • Google Ads & Meta Pixel Conversion setup


πŸš€ Step-by-Step Implementation


πŸ”Ή Step 1: Extract Email & Phone After Checkout

Edit catalog/controller/checkout/success.php and extract order data:

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

// Sanitize and hash
$email_clean = strtolower(trim($order_info['email']));
$phone_clean = preg_replace('/\D/', '', $order_info['telephone']);

$email_hashed = hash('sha256', $email_clean);
$phone_hashed = hash('sha256', $phone_clean);

βœ… This hashes PII before any browser exposure.


πŸ”Ή Step 2: Inject Hashed Data into success.twig

Pass hashed values to the template:

$data['user_hash_data'] = json_encode([
'email' => $email_hashed,
'phone' => $phone_hashed,
'event_id' => uniqid('purchase_', true)
]);

In success.twig, push to the dataLayer:

{% if user_hash_data %}
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'purchase',
user_data: {{ user_hash_data|raw }},
ecommerce: {
transaction_id: '{{ order_id }}',
value: '{{ total }}',
currency: '{{ currency }}'
}
});
</script>
{% endif %}

βœ… At this point, your GTM Web Container can access user_data.email and user_data.phone.


πŸ”Ή Step 3: Create GA4 and Ads Tags in Web GTM

Create GA4 Event Tag

  • Event Name: purchase
  • Parameters:
    • transaction_id, value, currency
    • Custom parameter: user_data_email, user_data_phone (if passing to GA4 directly)

βœ… More often, you’ll pass these directly to Server GTM, not GA4.

Trigger: Custom Event = purchase


πŸ”Ή Step 4: Send Data to Server-Side GTM

In GA4 Event Tag (Web), set:

Field Name Value
transport_url https://gtm.yoursite.com

βœ… This routes your purchase event and associated user_data to the server.


πŸ”Ή Step 5: Handle Data in Server-Side GTM

1. Create Variables:

  • Event Data β†’ user_data.email
  • Event Data β†’ user_data.phone
  • Event Data β†’ ecommerce.transaction_id
  • Event Data β†’ event_id

2. Create Tags:


πŸ…°οΈ Google Ads Enhanced Conversion (Server Tag)

  • Tag Type: Google Ads Conversion
  • Include:
    • email: {{ user_data.email }}
    • phone_number: {{ user_data.phone }}
    • transaction_id, currency, value, event_id
  • Trigger: purchase

βœ… Google will hash this again before processing.


πŸ…±οΈ Meta CAPI HTTP Request Tag

  • Use Meta CAPI tag template
  • Fields:
    • em: {{ user_data.email }}
    • ph: {{ user_data.phone }}
    • event_name: Purchase
    • event_id: {{ event_id }}
    • action_source: website
    • currency, value, transaction_id

βœ… Improves match quality in Meta by 30–40% for some accounts.


πŸ”Ή Step 6: Deduplicate and Validate

Use event_id to deduplicate conversions across:

  • Web β†’ Google Ads
  • Server β†’ Google Ads
  • Web β†’ Meta Pixel
  • Server β†’ Meta CAPI

Both platforms support deduplication based on event_id.


πŸ”Ή Step 7: Test Your Implementation

Use:

  • GA4 DebugView for real-time event monitoring
  • Server GTM Preview mode to verify incoming values
  • Meta CAPI Test Events in Events Manager
  • Google Ads Enhanced Conversion Troubleshooter (under Tools > Conversions)


πŸ” Security & Compliance Best Practices

Action Purpose
Hash emails/phones in backend Prevent raw PII exposure in browser
Use first-party domain (gtm.yoursite.com) Ensures cookies persist
Honor consent Only fire tags if user agrees
Log events in Server GTM Monitor anomalies
Use secure headers Restrict spoofed incoming traffic


πŸ“¦ Summary Flow

[OpenCart Checkout (PHP)]
↓
[Hash Email & Phone β†’ Twig β†’ dataLayer.push()]
↓
[Web GTM β†’ GA4 Tag β†’ Server Endpoint]
↓
[Server GTM]
↓ ↓
[Google Ads] [Meta CAPI]


πŸ§ͺ QA Checklist

Item Status
Email & phone hashed in backend βœ…
dataLayer push has user_data βœ…
GTM tags triggered with correct values βœ…
Server GTM receives and parses data βœ…
Tags sent to Meta and Google Ads βœ…
event_id used for deduplication βœ…


πŸ›‘οΈ Server-Side Tracking for Enhanced Attribution in a Privacy-First World

Standard

With privacy regulations like GDPR, CCPA, and browser changes (e.g., Safari’s ITP, Firefox ETP), traditional client-side tracking is no longer reliable. Users block cookies, disable JavaScript, or opt out of tracking entirely.

Server-side tracking provides a robust, privacy-conscious solution to improve attribution, ensure compliance, and deliver high-quality data across GA4, Google Ads, Meta CAPI, and other platforms.

🎯 Goals of Server-Side Tracking

  • Restore conversion attribution even when client-side is blocked
  • Respect consent while improving data fidelity
  • Maintain ad platform visibility (Google Ads, Meta Ads)
  • Enable first-party data enrichment and modeling


🧰 Requirements

  • A deployed Server-Side GTM container (gtm.yourdomain.com)
  • GA4 and Google Ads accounts
  • Consent management platform (CMP) or custom consent system
  • Web GTM container installed on site
  • OpenCart (or any other eCommerce platform) with customization access


πŸš€ Step-by-Step Guide


πŸ”Ή Step 1: Deploy Your Server-Side GTM Container

Use Google Cloud App Engine or a provider like Stape.io:

https://github.com/GoogleCloudPlatform/terraform-google-tag-manager

Example endpoint:
https://gtm.yourdomain.com

βœ… Set this domain as a first-party cookie server for better attribution.


πŸ”Ή Step 2: Update GA4 and Conversion Tags to Use Transport URL

In Web GTM:

  1. Modify your GA4 Configuration tag:
    • Add field: transport_url = https://gtm.yourdomain.com
  2. Modify Google Ads / Meta tags to also send data server-side (if applicable)

βœ… This routes tracking data through your server endpoint.


πŸ”Ή Step 3: Setup Consent-Aware Data Collection

Ensure that user consent is respected before sending data to the server:

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "default_consent",
ad_storage: "denied",
analytics_storage: "denied"
});

// After consent given
function onConsentGranted() {
dataLayer.push({
event: "update_consent",
ad_storage: "granted",
analytics_storage: "granted"
});
}

βœ… Integrate with your CMP (e.g., Cookiebot, OneTrust) to update consent dynamically.


πŸ”Ή Step 4: Capture User Identifiers (GCLID, FBC, Client_ID)

Use JS to extract and store first-party identifiers:

<script>
(function(){
const urlParams = new URLSearchParams(window.location.search);
const gclid = urlParams.get('gclid');
const fbc = urlParams.get('fbclid');

if (gclid) document.cookie = `gclid=${gclid}; path=/; max-age=2592000; SameSite=Lax`;
if (fbc) document.cookie = `fbc=${fbc}; path=/; max-age=2592000; SameSite=Lax`;
})();
</script>

βœ… These cookies are used server-side to match sessions with ad clicks.


πŸ”Ή Step 5: Send Conversion Events from Client to Server

Example purchase push (in success.twig):

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: '{{ order_id }}',
value: '{{ total }}',
currency: '{{ currency }}',
items: [
{% for product in products %}
{
item_id: '{{ product.model }}',
item_name: '{{ product.name|escape('js') }}',
price: '{{ product.price }}',
quantity: '{{ product.quantity }}'
}{% if not loop.last %},{% endif %}
{% endfor %}
]
},
user_data: {
email: '{{ customer.email|lower|sha256 }}',
phone: '{{ customer.telephone|sha256 }}',
client_id: '{{ ga_client_id }}',
gclid: '{{ gclid_cookie }}',
fbc: '{{ fbc_cookie }}'
},
event_id: 'oc_{{ order_id }}'
});
</script>

βœ… Use SHA256 hashing in PHP or JS for PII (email, phone) before pushing.


πŸ”Ή Step 6: Handle Events in Server GTM

In Server-Side GTM:

  1. Create Variables:
    • ecommerce.value
    • user_data.email
    • event_id
  2. Create Tags:
    • GA4 Server Tag β†’ Sends to GA4
    • Google Ads Conversion Tag β†’ Sends to Google Ads
    • Meta CAPI Tag (via HTTP Request Tag or Template)

Trigger Condition:
Event Name equals "purchase" and Consent granted = true


πŸ”Ή Step 7: Add HTTP Headers for Attribution Enrichment

Enable Request Headers in server GTM to read:

  • User-Agent
  • IP Address
  • Referer

βœ… This enhances matching accuracy in Meta, GA4, and Google Ads.


πŸ”Ή Step 8: Implement Conversion Deduplication

In all purchase events, include:

"event_id": "oc_{{order_id}}"

In server-side tags (Google Ads, GA4, Meta), map event_id so platforms can deduplicate conversions from multiple sources (e.g., client + server).


πŸ§ͺ QA Checklist

Item βœ…
GA4 uses transport_url βœ…
Event sent from client to server βœ…
Server GTM receives and processes βœ…
Consent checked before firing βœ…
event_id used for deduplication βœ…
Headers available in request βœ…
Matching identifiers present (gclid, client_id) βœ…


🧠 Pro Tips

Tip Why It Matters
Use hashed PII for privacy Enables matching without storing raw data
Set up logging in Server GTM Audit conversion flow
Whitelist trusted domains Prevent spoofed requests
Monitor via GA4 DebugView + GTM Server Preview Real-time validation
Always fallback to client-only if user denies consent Legal compliance


πŸ“¦ Architecture Summary

[Client Browser]
↓
[dataLayer β†’ Web GTM]
↓ β†˜
[Consent Check] [GA4 Tag β†’ transport_url=https://gtm.yourdomain.com]
↓
[Server-Side GTM Container]
↓ ↓ ↓
[GA4] [Google Ads] [Meta CAPI]


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

Standard

Tracking OpenCart checkout events accurately is critical for ad attribution, conversion optimization, and remarketing. By routing checkout data server-side using Server-Side Google Tag Manager (ssGTM), you gain resilient, ad-block-proof, and privacy-compliant tracking for platforms like GA4, Google Ads, Meta, and others.

βœ… Why Send Checkout Events Server-Side?

Benefit Description
Ad Blocker Resilience Bypasses client-side tag blockers
Accurate Attribution Ensures gclid/fbp match and timestamp
Privacy Control Filters/cleans data before reaching vendors
Enhanced Matching Passes hashed emails and first-party identifiers
Conversion Deduplication Server-side logic avoids double firing


🧰 Requirements

  • OpenCart store (v3.x or v4.x)
  • Server-Side GTM container deployed (e.g. via Stape or GCP)
  • Web GTM container already installed
  • GA4 and Google Ads accounts with conversion actions configured


πŸš€ Step-by-Step Implementation


πŸ”Ή Step 1: Capture Checkout Event in OpenCart (PHP)

Edit: catalog/controller/checkout/success.php

After successful order creation, extract transaction data:

$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'],
'price' => $product['price'],
'quantity' => $product['quantity']
];
}

$checkout_event = [
'event' => 'purchase',
'ecommerce' => [
'transaction_id' => $order_info['order_id'],
'value' => $order_info['total'],
'currency' => $order_info['currency_code'],
'items' => $items
],
'user_data' => [
'email' => $order_info['email'],
'phone' => $order_info['telephone']
]
];

Then pass to Twig for frontend use:

$data['gtm_purchase'] = json_encode($checkout_event);


πŸ”Ή Step 2: Push Checkout Event to Data Layer (Client Side)

In success.twig:

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


πŸ”Ή Step 3: Send Checkout Event to Server GTM (via Web GTM)

In Web GTM, create:

GA4 Purchase Event Tag:

  • Event Name: purchase
  • Event Parameters:
    • transaction_id, value, currency, items
  • Under Fields to Set, add:

Field Name Value
transport_url https://gtm.yoursite.com

βœ… This sends event to your Server GTM endpoint.


πŸ”Ή Step 4: Server GTM – Create GA4 Tag

In Server GTM Container:

  1. Tag Type: Google Analytics: GA4
  2. Trigger: Event Name equals purchase
  3. Parameters: Map from Event Data:
    • transaction_id, value, currency, items

This delivers the event to GA4 via measurement protocol.


πŸ”Ή Step 5: Server GTM – Create Google Ads Conversion Tag

In Server GTM:

  1. Tag Type: Google Ads Conversion
  2. Conversion ID/Label: From Google Ads UI
  3. Event Parameters:
    • transaction_id: {{Event Data β†’ ecommerce.transaction_id}}
    • value: {{Event Data β†’ ecommerce.value}}
    • currency: {{Event Data β†’ ecommerce.currency}}
  4. Trigger: When Event Name = purchase

βœ… This ensures conversion is sent server-side, even if user blocks JS.


πŸ”Ή Step 6: Optional – Enhance with User Matching

In user_data, include hashed values (email, phone) to improve match rates:

PHP Hashing:

$email_hashed = hash('sha256', strtolower(trim($order_info['email'])));
$phone_hashed = hash('sha256', preg_replace('/\D/', '', $order_info['telephone']));

Pass this in the user_data block:

'user_data' => [
'email' => $email_hashed,
'phone' => $phone_hashed
]

Then access in Server GTM via Event Data variables for Meta CAPI or Google Ads Enhanced Conversions.


πŸ”Ή Step 7: Deduplicate Conversions with event_id

Add a unique ID in PHP:

'event_id' => uniqid('oc_', true)

Send this to both:

  • Client-side GA4 tag (in GTM)
  • Server-side GA4/Google Ads tag (in Server GTM)

βœ… Prevents duplicate counting of the same conversion.


πŸ§ͺ QA Checklist

Step Validation
purchase event in success.twig βœ…
GA4 tag uses transport_url βœ…
Server GTM receives event βœ…
GA4 DebugView shows event βœ…
Google Ads receives conversion βœ…
Values (revenue, ID, currency) match βœ…
event_id deduplication logic present βœ…


🧠 Pro Tips

Tip Benefit
Use first-party subdomain (e.g., gtm.yoursite.com) Improves cookie lifespan
Send user_id if available Enables cross-device GA4 tracking
Track refunds similarly Close the loop for revenue reporting
Log events server-side Debug attribution gaps
Enable consent mode for GDPR regions Ensures legal compliance


πŸ“¦ Summary Flow

[OpenCart Checkout Success]
↓
[PHP β†’ JS dataLayer β†’ Web GTM]
↓ ↓
[GA4 Client Tag] [Server Request to gtm.yoursite.com]
↓
[Server GTM Container]
↓ ↓
[GA4] [Google Ads]


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

Standard

Implementing Server-Side Google Tag Manager (ssGTM) in OpenCart significantly enhances data security, load speed, and tracking accuracy. When paired with GA4 and Google Ads, it provides improved attribution, first-party data reliability, and conversion resilience in a cookieless world.

βœ… Why Server-Side GTM for OpenCart?

Advantage Benefit
First-party cookies Resilient tracking in Safari/Firefox
Data control Filter bots, enrich or mask PII
Faster site speed Moves heavy tags off the client
Ad blocker evasion Improves event delivery
Enhanced conversion tracking Improves Google Ads ROI


🧰 Requirements

  • A Server-Side GTM container (setup on Google Cloud or other endpoint)
  • OpenCart store with GTM web container installed
  • Access to .twig and PHP files in OpenCart
  • GA4 and Google Ads accounts


πŸš€ Step-by-Step Implementation


πŸ”Ή Step 1: Deploy Server-Side GTM Tagging Server

Option 1: Google Cloud App Engine

  1. Clone GTM server container:
    https://github.com/GoogleCloudPlatform/terraform-google-tag-manager
  2. Deploy via CLI or console
  3. Your tagging server URL will look like:
    https://gtm.example.com

Option 2: Use a 3rd Party (e.g., Stape.io, GTM-Server)

  • Faster and easier, especially for non-technical deployment


πŸ”Ή Step 2: Update GA4 Web Tag in GTM to Use Server Container

  1. In Web GTM, locate your GA4 Configuration tag
  2. Under Fields to Set, add: Field NameValuetransport_urlhttps://gtm.example.com
  3. This ensures GA4 data flows to the server endpoint instead of Google directly


πŸ”Ή Step 3: Setup Web Container Events in OpenCart (Client-Side)

In product.twig (view_item example):

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'view_item',
ecommerce: {
items: [{
item_id: '{{ product.model }}',
item_name: '{{ product.name }}',
price: '{{ product.price }}',
currency: '{{ session.currency }}'
}]
}
});
</script>

Configure similar pushes for:

  • add_to_cart
  • begin_checkout
  • purchase

Use success.twig for purchases.


πŸ”Ή Step 4: Setup GA4 Event Tags in GTM (Client)

  • Use GA4 Event Tags for each event (view_item, add_to_cart, purchase)
  • All should use the GA4 config tag with updated transport_url
  • Trigger via Custom Events based on dataLayer pushes


πŸ”Ή Step 5: Enable GA4 Server Container Tag

In your Server Container:

  1. Create a GA4 tag with type β€œGoogle Analytics: GA4”
  2. Set it to trigger on All Events
  3. In Settings, paste your GA4 Measurement ID
  4. Save and publish

βœ… This processes incoming GA4 events from client GTM


πŸ”Ή Step 6: Setup Google Ads Conversion Tag in Server GTM

  1. In Server Container, click Tags β†’ New β†’ Google Ads Conversion
  2. Enter:
    • Conversion ID
    • Conversion Label
  3. Set trigger: Event Name equals purchase (or a custom condition)
  4. Under Event Data, use variables like:

transaction_id: {{Event Data β†’ ecommerce.transaction_id}}
value: {{Event Data β†’ ecommerce.value}}
currency: {{Event Data β†’ ecommerce.currency}}


πŸ”Ή Step 7: Pass Client Identifiers from OpenCart to GTM

In header.twig or globally:

<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
client_id: '{{ ga_client_id_from_cookie }}',
gclid: '{{ gclid_from_url }}'
});
</script>

Use GTM variables to pass these to the server:

  • client_id β†’ GA4 user linkage
  • gclid β†’ Google Ads attribution


πŸ”Ή Step 8: Send Data from Client GTM β†’ Server GTM

In Client GTM:

  • Use a GA4 Event Tag
  • Set transport_url
  • Add client_id, user_properties, items, etc.

In Server GTM:

  • Use Event Data variables to extract info
  • Route to GA4 or Google Ads tags


πŸ” Debug & QA

  1. Use GA4 DebugView to ensure events are processed
  2. Open Server GTM’s Preview mode (via Tag Assistant)
  3. Check the Network tab in browser to confirm data is routed to https://gtm.example.com/g/collect?...


🧠 Pro Tips

Tip Why It Helps
Use first-party subdomain like gtm.yoursite.com Boosts cookie reliability
Add headers like IP & User-Agent in server GTM Improves Google Ads attribution
Deduplicate server-side events with event ID Prevents double tracking
Track login or user ID in user_properties Enables cross-device GA4 tracking


πŸ§ͺ QA Checklist

Step Status
Server container deployed βœ…
GA4 web tags using transport_url βœ…
GA4 server tag created βœ…
Purchase events routed to GA4 & Ads βœ…
Conversion fires server-side βœ…


πŸ“¦ Summary Architecture

[OpenCart Frontend]
↓
[dataLayer β†’ Web GTM]
↓
[GA4 Config Tag β†’ transport_url=https://gtm.example.com]
↓
[Server-Side GTM Container]
↓ ↓
[GA4 Server Tag] [Google Ads Server Tag]


🎯 OpenCart Conversion Optimization Using GA4 Exploration Reports

Standard

Conversion optimization on OpenCart goes beyond tracking clicks and transactionsβ€”it’s about uncovering behavior patterns, friction points, and drop-offs across the funnel. With GA4 Exploration Reports, you can build custom views of user journeys and identify exactly where users are losing interest or converting.

βœ… Why GA4 Explorations Matter for CRO

GA4 Report Type CRO Use Case
Funnel Exploration Identify drop-offs in multi-step checkout
Path Exploration Discover unexpected user paths or loops
Segment Overlap Compare behaviors across traffic sources
Free-form Table Compare conversion rates by landing page


🧰 Prerequisites

  • GA4 property connected to your OpenCart site
  • GTM web container installed
  • Enhanced eCommerce events: view_item, add_to_cart, begin_checkout, purchase
  • GA4 base tag and event tags configured via GTM
  • Optionally track micro conversions (scroll, cta_click, form_submit)


πŸš€ Step-by-Step Implementation


πŸ”Ή Step 1: Ensure Key Conversion Events Are Tracked

You should have the following events already firing via GTM:

  • view_item
  • add_to_cart
  • begin_checkout
  • purchase

Example Data Layer Push for begin_checkout:

$data['gtm_begin_checkout'] = json_encode([
'event' => 'begin_checkout',
'ecommerce' => [
'currency' => $this->session->data['currency'],
'items' => array_map(function($product) {
return [
'item_id' => $product['model'],
'item_name' => $product['name'],
'price' => $product['price'],
'quantity' => $product['quantity']
];
}, $this->cart->getProducts())
]
]);

Twig Output (in checkout.twig):

{% if gtm_begin_checkout %}
<script>dataLayer.push({{ gtm_begin_checkout|raw }});</script>
{% endif %}


πŸ”Ή Step 2: Track Micro-Conversions (Optional but Powerful)

Add events like:

  • scroll_depth_75
  • cta_click
  • newsletter_signup
  • payment_option_selected

Example scroll tracking (JavaScript):

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

Create GTM tags for each event using GA4 Event tags and mark them as conversions in GA4 if relevant.


πŸ”Ή Step 3: Mark Conversion Events in GA4

  1. Go to GA4 Admin β†’ Events
  2. Locate events like purchase, begin_checkout, cta_click
  3. Toggle Mark as Conversion on for each

βœ… This enables them for inclusion in funnel and path reports.


πŸ”Ή Step 4: Build Funnel Exploration Reports

Go to Explore β†’ Funnel Exploration and click Create New Funnel.

Example Funnel:

Step Event Name Description
Step 1 view_item Product page viewed
Step 2 add_to_cart Item added to cart
Step 3 begin_checkout Checkout started
Step 4 purchase Transaction completed

Settings:

  • Choose “Open Funnel” to allow users to enter at any step
  • Set Breakdown by:
    • device category
    • source/medium
    • product category


πŸ”Ή Step 5: Create Path Exploration Reports

Go to Explore β†’ Path Exploration.

Start from event: session_start or page_view
OR
End at event: purchase

GA4 will display user paths leading to or from that point. Use it to:

  • Detect common exits after add_to_cart
  • See loops between cart and checkout
  • Identify unexpected navigation paths


πŸ”Ή Step 6: Segment Audiences for CRO Insights

Go to Explore β†’ Free Form and apply segments like:

  • Users from Facebook / CPC vs Google / Organic
  • Mobile users vs Desktop
  • Returning vs New users
  • Sessions with add_to_cart but no purchase

Compare metrics like:

  • Conversion rate
  • Avg. engagement time
  • Events per session


πŸ”Ή Step 7: Take CRO Action Based on Insights

Insight CRO Action
High drop-off at add_to_cart Add trust badges, enable guest checkout
Low CTA click on mobile Increase button size, improve contrast
Low engagement on product pages Add video, reviews, or FAQs
Low conversion from organic traffic Improve landing page match to search intent


🧠 Pro Tips

Tip Why It Matters
Track micro-conversions Helps diagnose intent even without purchases
Use custom dimensions for CTA text/version A/B test and attribute results
Combine Funnel + Path reports See both structured and natural flows
Use GA4 DebugView before publishing tags Validate data collection end-to-end


πŸ§ͺ QA Checklist

Item Status
All key events fire via GTM βœ…
GA4 shows conversion events βœ…
Funnel exploration created βœ…
Path exploration populated βœ…
Segment comparisons set up βœ…
Action items derived from insights βœ…


πŸ“¦ Summary Table

GA4 Tool CRO Use Case
Funnel Exploration Drop-off points in checkout
Path Exploration Navigation loops and leaks
Segment Comparison Behavioral differences by source
Event Tracking Measure micro and macro success signals


πŸ§ͺ OpenCart CRO: A/B Testing CTA Events & Conversions Using GTM

Standard

A/B testing your Call-to-Action (CTA) elements is one of the most impactful CRO strategies for OpenCart. Whether it’s testing different button text, colors, or placements, integrating Google Tag Manager (GTM) with GA4 lets you track variant-specific performance and conversionsβ€”without needing a third-party testing tool.

🎯 Use Case Example

You want to test two CTA buttons on your product page:

  • Variant A: “Buy Now” (original)
  • Variant B: “Get Yours Today” (test version)

You’ll randomize visitors, track which CTA they saw, and measure clicks + conversions.


βœ… What You’ll Set Up

Component Implementation
A/B Variant Assignment JavaScript with cookie
DataLayer Push Variant info + CTA click
GA4 Event cta_click with variant parameter
GA4 Funnel Conversions per variant
Reporting GA4 Explorations or Looker Studio


🧰 Requirements

  • OpenCart v3.x or v4.x
  • Google Tag Manager installed sitewide
  • GA4 tag implemented via GTM
  • Editable .twig product or landing page
  • Consent mode compliance (recommended)


πŸš€ Step-by-Step Implementation


πŸ”Ή Step 1: Inject A/B Variant Logic with JavaScript

In your product.twig or any target .twig page:

<script>
(function() {
const abCookie = 'cta_variant';
const variants = ['A', 'B'];

function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
return parts.length > 1 ? parts.pop().split(';').shift() : null;
}

function setCookie(name, value, days) {
const d = new Date();
d.setTime(d.getTime() + (days*24*60*60*1000));
document.cookie = `${name}=${value}; path=/; max-age=${days*86400}`;
}

let assignedVariant = getCookie(abCookie);
if (!assignedVariant) {
assignedVariant = variants[Math.floor(Math.random() * variants.length)];
setCookie(abCookie, assignedVariant, 7);
}

// Render variant-specific CTA
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'ab_variant_assigned',
variant: assignedVariant
});

window.addEventListener('DOMContentLoaded', function() {
const ctaContainer = document.querySelector('#cta-button');

if (assignedVariant === 'A') {
ctaContainer.innerHTML = `<button id="btn-cta" class="btn btn-primary">Buy Now</button>`;
} else {
ctaContainer.innerHTML = `<button id="btn-cta" class="btn btn-success">Get Yours Today</button>`;
}

document.getElementById('btn-cta').addEventListener('click', function() {
window.dataLayer.push({
event: 'cta_click',
variant: assignedVariant
});
});
});
})();
</script>

βœ… This:

  • Randomly assigns a variant
  • Persists it in a cookie
  • Pushes the ab_variant_assigned and cta_click events to the dataLayer


πŸ”Ή Step 2: Add CTA Button Container in HTML

In the same .twig file:

<div id="cta-button"></div>


πŸ”Ή Step 3: Set Up GTM Data Layer Variables

In GTM, create these variables:

Variable Name Data Layer Variable Name
DLV - variant variant

βœ… These will be used in both tag triggers and GA4 parameters.


πŸ”Ή Step 4: Create GA4 Event Tags

1. Variant Assignment Tag

  • Tag Type: GA4 Event
  • Event Name: ab_variant_assigned
  • Parameter:
    • variant: {{DLV - variant}}
  • Trigger: Custom Event β†’ ab_variant_assigned

2. CTA Click Tag

  • Tag Type: GA4 Event
  • Event Name: cta_click
  • Parameter:
    • variant: {{DLV - variant}}
  • Trigger: Custom Event β†’ cta_click


πŸ”Ή Step 5: Mark CTA Clicks as Conversions in GA4

  1. Go to GA4 β†’ Admin β†’ Events
  2. Locate cta_click
  3. Toggle Mark as conversion


πŸ”Ή Step 6: Funnel Reporting in GA4 Explorations

Go to Explore β†’ Free Form or Funnel and configure:

Funnel Steps:

  1. ab_variant_assigned
  2. cta_click
  3. purchase (optional)

Breakdown by: variant

βœ… This will show conversion rates for each CTA variant.


πŸ”Ή Step 7: Optional – Retarget Based on Variant

In GA4:

  • Create an audience: users who saw Variant B but didn’t purchase
  • Push to Google Ads for personalized retargeting


🧠 Pro Tips

Tip Value
Use persistent cookies for consistent variant exposure Prevent test contamination
Always push both assignment + click events Enables clear funnel attribution
Use different CTA button styles/colors Amplify visual impact
Combine with GA4 scroll, engagement data Deeper insight into user intent
Export to Looker Studio for stakeholder reporting Sharper data storytelling


πŸ§ͺ QA Checklist

Test βœ…
Cookie sets cta_variant on first visit βœ…
ab_variant_assigned event fires βœ…
Correct button rendered based on variant βœ…
cta_click event pushes to dataLayer βœ…
GA4 receives both events with correct variant βœ…
Funnel comparison by variant works βœ…


πŸ“¦ Summary Table

Component Description
JavaScript Randomly assigns CTA variant
GTM Events ab_variant_assigned, cta_click
GA4 Funnel Analyze CTA click β†’ conversion per variant
Reporting GA4 Exploration + Looker Studio