OpenCart: OpenAI Ads Pixel and CAPI for OpenCart: Complete Setup
OpenCart is loved for being lightweight and fast. But when it comes to tracking conversions on paid AI channels like ChatGPT Ads, that simplicity can work against you. Most OpenCart stores rely on third-party payment gateways like PayPal, Authorize.net, or local European bank processors. These gateways redirect shoppers away from your store to pay, and many shoppers close their mobile tabs the second their payment confirms.
They never make it back to index.php?route=checkout/success.
The purchase happened, the inventory deducted, but your ad tracking recorded nothing. If your ad account misses 20% of your sales, your cost per acquisition looks falsely inflated, and campaign optimization stalls.
The solution is straightforward: use header.twig and success.twig for frontend browser events, and bind a backend listener to OpenCart's addOrderHistory/after event hook. That way, the moment your database registers an order as paid, your server dispatches the conversion directly to OpenAI's Conversions API (CAPI). Here is the full implementation guide for OpenCart 3.x and 4.x.
1. OpenCart Event Mapping Table
| Customer Action | OpenCart Trigger Point | OpenAI Ads Event | Delivery Method |
|---|---|---|---|
| View Storefront | common/header.twig | page_viewed | Browser Pixel |
| View Product Details | product/product.twig | contents_viewed | Browser Pixel |
| Add to Cart | AJAX cart.add response | items_added | Browser Pixel |
| Load Checkout | checkout/checkout.twig | checkout_started | Browser Pixel |
| Order Success Page | checkout/success.twig | order_created | Browser Pixel |
| Order Payment Status Updated | addOrderHistory/after Event | order_created | Server CAPI (cURL) |
2. Installing the Base Measurement Pixel
Inject the base pixel into catalog/view/theme/YOUR_THEME/template/common/header.twig before the closing </head> tag:
<script>
!function(w,d,e,v,n,t,s){if(w.oaiq)return;n=w.oaiq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!w._oaiq)w._oaiq=n;
n.push=n;n.loaded=!0;n.version='1.0';n.queue=[];t=d.createElement(e);t.async=!0;
t.src=v;s=d.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}
(window,document,'script','https://bzrcdn.openai.com/pixel.js');
oaiq('init', 'YOUR_OPENAI_PIXEL_ID');
oaiq('event', 'page_viewed');
</script>
3. Order Success Page Tracking (checkout/success.twig)
When a customer successfully completes checkout and lands on the order confirmation screen, fire the client-side order_created event:
{% if order_id %}
<script>
if (window.oaiq) {
window.oaiq('event', 'order_created', {
order_id: '{{ order_id }}',
event_id: 'oc_order_{{ order_id }}'
});
}
</script>
{% endif %}
4. Server-Side CAPI Implementation via OpenCart Events
Never edit core model files directly. OpenCart's Event system allows you to intercept order status changes cleanly:
A. Register the Event in OpenCart Admin
In OpenCart 3 or 4:
- Navigate to Extensions > Events (or configure via an extension installer XML).
- Register an event on
catalog/model/checkout/order/addOrderHistory/afterpointing to your controller methodextension/analytics/openai_ads/onOrderHistoryChange.
B. Controller Implementation
In catalog/controller/extension/analytics/openai_ads.php:
<?php
class ControllerExtensionAnalyticsOpenaiAds extends Controller {
public function onOrderHistoryChange(&$route, &$args, &$output) {
$order_id = isset($args[0]) ? (int)$args[0] : 0;
$order_status_id = isset($args[1]) ? (int)$args[1] : 0;
if (!$order_id) return;
// Ensure this only triggers for paid order statuses (e.g. Processing = 2, Complete = 5)
$paid_statuses = [2, 5];
if (!in_array($order_status_id, $paid_statuses)) return;
$this->load->model('checkout/order');
$order_info = $this->model_checkout_order->getOrder($order_id);
if (!$order_info) return;
$pixel_id = 'YOUR_OPENAI_PIXEL_ID';
$capi_key = 'YOUR_OPENAI_CAPI_KEY';
$endpoint = 'https://bzr.openai.com/v1/events?pid=' . $pixel_id;
$amount_cents = (int)round(((float)$order_info['total']) * 100);
$email = strtolower(trim($order_info['email']));
$dedup_key = 'oc_order_' . $order_id; // Matches browser event_id
$payload = [
'validate_only' => false,
'events' => [
[
'id' => 'srv_oc_' . $order_id . '_' . time(),
'type' => 'order_created',
'timestamp_ms' => (int)round(microtime(true) * 1000),
'action_source' => 'website',
'event_id' => $dedup_key,
'user_data' => [
'em' => hash('sha256', $email),
'client_ip_address' => $order_info['ip'],
'country' => strtolower($order_info['payment_iso_code_2'])
],
'data' => [
'amount' => $amount_cents,
'currency' => $order_info['currency_code'],
'order_id' => (string)$order_id
]
]
]
];
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_TIMEOUT, 4);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $capiKey,
'Content-Type: application/json'
]);
curl_exec($ch);
curl_close($ch);
}
}
5. Deduplication and Verification
OpenCart stores both the front-end success screen and back-end order notification under event_id: "oc_order_" . $order_id.
When the buyer lands on the success page, the browser sends the conversion along with the first-party click attribution cookie. When the backend receives the IPN or webhook and calls addOrderHistory/after, CAPI sends the verified server-side total with the same event_id. OpenAI's platform automatically deduplicates the pair and records one accurate sale.
If the buyer closes their tab early or an ad blocker blocks success.twig, your backend event guarantees the sale is captured.
Need assistance configuring your OpenCart tracking pipeline? Explore our Done-For-You Ecommerce Tracking service.
Want this done for you?
Fixed-scope setup, tested end-to-end and documented.
Explore the serviceTake the free audit