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:
- Tag Type: Google Analytics: GA4
- Trigger: Event Name equals
purchase - 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:
- Tag Type: Google Ads Conversion
- Conversion ID/Label: From Google Ads UI
- Event Parameters:
transaction_id:{{Event Data โ ecommerce.transaction_id}}value:{{Event Data โ ecommerce.value}}currency:{{Event Data โ ecommerce.currency}}
- 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]
