Most eCommerce setups only send purchase data to analytics platforms, leaving out one critical part of the picture: refunds and returns. Without refund tracking, your Return on Ad Spend (ROAS) is inflated and misleading, especially when using platforms like Google Ads, Meta, and GA4.
By using Server-Side Tagging with OpenCart, we can accurately track refunded transactions and send them back to your analytics toolsβensuring true revenue-based attribution.
β Why Track Refunds?
Reason | Impact |
---|---|
Clean ROAS | Exclude refunded revenue from conversions |
GA4 Attribution Accuracy | Maintain realistic funnel reporting |
Google Ads Optimization | Avoid over-optimized bids for refunded conversions |
Meta Ads CAPI | Refund signals improve campaign quality |
π§° Requirements
Item | Description |
---|---|
OpenCart | Version 3.x or 4.x |
Server-Side GTM | Configured on a first-party domain |
Google Ads, Meta CAPI, GA4 | Platforms integrated |
Order Status Logic | To determine when an order is refunded |
Consent Layer (Optional) | To handle GDPR/CCPA compliance |
π§± Step 1: Detect Refunded Orders in OpenCart Admin
Modify the refund trigger. In OpenCart, you can hook into order status updates.
In admin/controller/sale/order.php
, locate or add code where order status is updated to βRefundedβ (you may need to define a custom status ID, e.g., 11
):
if ($order_status_id == 11) { // 11 = Refunded
$order_info = $this->model_sale_order->getOrder($order_id);
$products = $this->model_sale_order->getOrderProducts($order_id);
$items = [];
foreach ($products as $product) {
$items[] = [
'item_id' => $product['model'],
'item_name' => $product['name'],
'quantity' => $product['quantity'],
'price' => $product['price']
];
}
$refund_payload = [
'event_name' => 'refund',
'event_id' => uniqid('refund_', true),
'transaction_id' => $order_info['order_id'],
'currency' => $order_info['currency_code'],
'value' => -1 * $order_info['total'],
'items' => $items
];
$this->sendRefundToServer($refund_payload);
}
π Step 2: Send Refund Event to Server-Side GTM
Add this custom helper function in the same file or a reusable module:
private function sendRefundToServer($payload) {
$ch = curl_init('https://gtm.yourdomain.com/event');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type:application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
β This will trigger every time an order is marked as refunded.
π§ Step 3: Parse Refunds in Server GTM
In your Server Container:
- Use the HTTP Request Client
- Match incoming event where
event_name = refund
- Extract
transaction_id
,items
,value
,currency
, andevent_id
π€ Step 4: Send Refund Event to GA4 via Server GTM
Create a GA4 Event Tag in ssGTM:
Parameter | Value |
---|---|
Event Name | refund |
Transaction ID | {{transaction_id}} |
Value | {{value}} |
Currency | {{currency}} |
Items | {{items}} |
Event ID | {{event_id}} |
β This removes refunded purchase value from revenue reports in GA4.
π― Step 5: Send Refund to Google Ads
In ssGTM:
- Create a Google Ads Conversion Tag
- Configure:
- Conversion ID / Label
transaction_id
:{{transaction_id}}
value
:{{value}}
(should be negative)currency
:{{currency}}
event_id
:{{event_id}}
(deduplication)
β This tells Google Ads the conversion has been reversed.
π Step 6: Send Refund Event to Meta Conversions API
Use the Meta HTTP tag or a Custom Request:
POST https://graph.facebook.com/v18.0/<PIXEL_ID>/events?access_token=<TOKEN>
{
"data": [{
"event_name": "Refund",
"event_time": {{ timestamp }},
"event_id": "{{event_id}}",
"action_source": "website",
"custom_data": {
"transaction_id": "{{transaction_id}}",
"currency": "{{currency}}",
"value": -99.00
}
}]
}
β Meta will treat it as a revenue correction.
π‘οΈ Step 7: Consent-Safe Processing
If you’re passing PII (e.g., email for Enhanced Conversions), add this logic:
if ($user_consent_given) {
$payload['email'] = hash('sha256', strtolower($order_info['email']));
}
Or handle consent_granted
logic in ssGTM to block tags if needed.
π§ͺ Step 8: QA Your Refund Events
Tool | What to Check |
---|---|
ssGTM Preview | Inspect payload structure |
GA4 DebugView | Look for real-time refund event |
Google Ads Conversion Tag Diagnostics | Check negative conversion |
Meta Events Manager β Test Events | View refund test data |
π Sample Refund Data Sent
{
"event_name": "refund",
"event_id": "refund_664c49d1a3bc9",
"transaction_id": "ORD12842",
"value": -99.99,
"currency": "USD",
"items": [{
"item_id": "PROD001",
"item_name": "Winter Jacket",
"price": 99.99,
"quantity": 1
}]
}
β Benefits Summary
Feature | Benefit |
---|---|
True ROAS Calculation | Filter out refunded revenue |
Attribution Accuracy | GA4 funnel metrics adjusted |
Ads Optimization | Less bias in Smart Bidding or CAPI |
First-Party Secure | No exposure of refund logic in frontend |
Works with All Platforms | Google Ads, Meta, GA4, and others |