Ecwid: OpenAI Ads Pixel and CAPI for Ecwid Stores: Complete Setup
Ecwid by Lightspeed makes it easy to drop an online store into any CMS, from WordPress and Wix to custom Webflow sites. But that embedded architecture is an absolute nightmare for paid ad tracking. Because Ecwid runs inside a cross-domain iframe or dynamic JavaScript container, third-party cookies get blocked on iOS, Safari, and Brave by default. If a shopper pays via PayPal or Klarna and closes the tab before returning to your thank-you page, client-side scripts miss the sale entirely.
That leaves 20% to 35% of your OpenAI Ads revenue unaccounted for.
To fix this, you need a dual-channel tracking setup. You hook the browser pixel (oaiq) into Ecwid's JavaScript Storefront API (Ecwid.OnOrderPlaced) for real-time attribution, and pipe a server-side webhook subscribing to order.created straight into OpenAI's Conversions API (/v1/events). Pass an identical event_id (ecwid_order_{orderNumber}) on both sides, and OpenAI will match them cleanly without double-counting a dime.
Browser Telemetry (Ecwid JS API)
│
▼
[Ecwid Storefront Widget] ──(bzrcdn.openai.com)──► Client Pixel (Pageview, ViewContent, AddToCart)
│
▼ Ecwid.OnOrderPlaced (Front-end confirmation)
Browser Pixel Purchase (event_id: ecwid_order_1042)
│
▼ Server Webhook (order.created)
[Cloudflare Worker / Lambda Relay]
│
▼ cURL POST (event_id: ecwid_order_1042)
OpenAI Ads Conversions API (https://bzr.openai.com/v1/events)
Part 1: Client-Side Pixel Setup via Ecwid Custom Script
In your Ecwid Admin, go to Settings > General > Tracking & Analytics (or your parent site's header). Inject the following base pixel script and Ecwid event listeners:
<script>
!function(w,d,e,u,t,s){if(w.openaiAds)return;t=w.openaiAds=function(){
t.callMethod?t.callMethod.apply(t,arguments):t.queue.push(arguments)};
if(!w._openaiAds)w._openaiAds=t;t.push=t;t.loaded=!0;t.version='1.0';
t.queue=[];s=d.createElement(e);s.async=!0;s.src=u;
var f=d.getElementsByTagName(e)[0];f.parentNode.insertBefore(s,f);
}(window,document,'script','https://bzrcdn.openai.com/pixel.js');
openaiAds('init', 'PIXEL_ID_HERE');
openaiAds('track', 'PageView');
// Ecwid Storefront API Listeners
window.Ecwid = window.Ecwid || [];
window.Ecwid.OnPageLoaded = window.Ecwid.OnPageLoaded || [];
window.Ecwid.OnPageLoaded.push(function(page) {
if (page.type === 'PRODUCT') {
openaiAds('track', 'ViewContent', {
content_type: 'product',
content_ids: [page.productId.toString()],
content_name: page.name,
value: Math.round((page.price || 0) * 100),
currency: 'USD'
});
}
});
// Purchase tracking with deterministic event_id
window.Ecwid.OnOrderPlaced = window.Ecwid.OnOrderPlaced || [];
window.Ecwid.OnOrderPlaced.push(function(order) {
var eventId = 'ecwid_order_' + order.orderNumber;
openaiAds('track', 'Purchase', {
currency: order.currency || 'USD',
value: Math.round(order.total * 100),
order_id: order.orderNumber.toString(),
content_ids: (order.items || []).map(function(item) { return item.id.toString(); }),
content_type: 'product'
}, {
event_id: eventId
});
});
</script>
Part 2: Server-Side CAPI via Ecwid Webhook Relay
To capture offloaded purchases and external payment returns, configure an Ecwid webhook relaying events directly to the OpenAI Ads Conversions API.
[Ecwid Cloud Engine]
│
▼ order.created Webhook
[Cloudflare Worker / Lambda Relay]
│
▼ Normalize, SHA-256 Hash, Format minor units
[OpenAI Ads CAPI Endpoint (https://bzr.openai.com/v1/events)]
Step 1: Create Edge Worker (Cloudflare Worker Example)
export default {
async fetch(request, env) {
if (request.method !== 'POST') {
return new Response('Method Not Allowed', { status: 405 });
}
try {
const ecwidOrder = await request.json();
// Ensure this is an order payload
if (!ecwidOrder || !ecwidOrder.orderNumber) {
return new Response('Invalid payload', { status: 400 });
}
const orderNumber = ecwidOrder.orderNumber;
const eventId = `ecwid_order_${orderNumber}`;
// User data hashing helper
const hashSha256 = async (str) => {
if (!str) return null;
const buffer = new TextEncoder().encode(str.trim().toLowerCase());
const hash = await crypto.subtle.digest('SHA-256', buffer);
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
};
const email = ecwidOrder.email;
const hashedEmail = await hashSha256(email);
let hashedPhone = null;
if (ecwidOrder.billingPerson && ecwidOrder.billingPerson.phone) {
const cleanPhone = ecwidOrder.billingPerson.phone.replace(/[^0-9]/g, '');
hashedPhone = await hashSha256(cleanPhone);
}
const valueMinor = Math.round(Number(ecwidOrder.total) * 100);
const currency = ecwidOrder.currency || 'USD';
const contentIds = (ecwidOrder.items || []).map(item => item.productId.toString());
const capiPayload = {
data: [
{
event_name: 'Purchase',
event_time: Math.floor(Date.now() / 1000),
event_id: eventId,
user_data: {
...(hashedEmail && { em: hashedEmail }),
...(hashedPhone && { ph: hashedPhone })
},
custom_data: {
currency: currency,
value: valueMinor,
order_id: orderNumber.toString(),
content_ids: contentIds,
content_type: 'product'
},
action_source: 'system_generated'
}
]
};
const response = await fetch('https://bzr.openai.com/v1/events', {
method: 'POST',
headers: {
'Authorization': `Bearer ${env.OPENAI_ADS_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(capiPayload)
});
return new Response('Event Dispatched', { status: response.status });
} catch (err) {
return new Response('Internal Error: ' + err.message, { status: 500 });
}
}
};
Deduplication and Verification
- Shared ID Formula: Both the front-end snippet and the backend webhook handler format the identifier as
ecwid_order_{orderNumber}. - Minor Units Verification: A purchase of $49.50 must output
4950as an integer. - Header Check: Verify
Authorization: Bearer <TOKEN>on every backend call.
Frequently Asked Questions
Where do I paste the OpenAI Ads Pixel code in Ecwid?
In your Ecwid Admin, navigate to Settings > General > Tracking & Analytics, or paste the script into the Custom JavaScript tracking code section under Design if you are using an instant site.
How do I track Ecwid store purchases with OpenAI Ads Pixel?
Listen to the native Ecwid JavaScript event Ecwid.OnOrderPlaced.byStore(function(order) { ... }) to capture orderNumber, total, currency, and items, firing openaiAds('track', 'Purchase', {...}).
How do I set up OpenAI Ads CAPI for Ecwid without direct server access?
Subscribe to Ecwid order.created webhooks using a lightweight cloud function (Cloudflare Worker or AWS Lambda), reformat the order payload to OpenAI CAPI specifications, and POST to https://bzr.openai.com/v1/events.
How does event deduplication work between Ecwid browser tracking and webhooks?
Both the Ecwid.OnOrderPlaced callback and the order.created webhook function pass event_id: ecwid_order_ + order.orderNumber, guaranteeing deduplication.
Want this done for you?
Fixed-scope setup, tested end-to-end and documented.
Explore the serviceTake the free audit