Tracking ChatGPT ads with the OpenAI pixel and Conversions API

OpenAI's ChatGPT ads come with two tracking options: a JavaScript pixel and a server-side Conversions API. Here's how to implement both, and why hybrid wins.

Share Post
Post By
Matthew Redford

OpenAI started serving ads inside ChatGPT in February 2026. The rollout was small, US-only, and limited to logged-in Free and Go users. Six months on, OpenAI has opened a self-serve Ads Manager, and most advertisers running paid social will eventually need to think about how to measure conversions from this surface.

This post is an implementation guide. It walks through installing the OpenAI measurement pixel, adding the events that matter for your business, and layering on the Conversions API for the conversions the pixel will miss.

Where ChatGPT ads sit right now

ChatGPT ads remain US-first. The EU is not yet in scope, which OpenAI puts down to the stricter consent and tracking requirements under GDPR and the ePrivacy Directive. If your audience is mainly European you can park this for now, but UK and US-facing accounts should be ready.

The mechanics are familiar. A user clicks an ad, lands on your site, and you tell OpenAI what happened next. The supported events look a lot like Meta and Google Ads: page views, content views, ecommerce events, lead and registration events, subscription events, and a custom event slot.

Step 1: install the measurement pixel

The pixel is a browser SDK loaded from https://bzrcdn.openai.com/sdk/oaiq.min.js. Get your Pixel ID from the conversions tab in your Ads Manager account, then drop this snippet into the <head> of every page you want to track. Put it as high in the <head> as practical so early conversions are not lost while other content loads.

<script>
 (function (w, d, s, u) {
   if (w.oaiq) return;
   var q = function () { q.q.push(arguments); };
   q.q = [];
   w.oaiq = q;
   var js = d.createElement(s);
   js.async = true;
   js.src = u;
   var f = d.getElementsByTagName(s)[0];
   f.parentNode.insertBefore(js, f);
 })(window, document, "script", "https://bzrcdn.openai.com/sdk/oaiq.min.js");

 oaiq("init", {
   pixelId: "<YOUR-PIXEL-ID>"
 });
</script>

Add debug: true to the init call while you are testing, so the SDK logs activity to the browser console.

Once the snippet is live, the pixel handles a few things on its own. It captures the oppref parameter from the landing URL, stores it in a first-party __oppref cookie, attaches the page origin as source_url, and timestamps each event. None of that needs wiring yourself.

Step 2: send a page view

The pixel does not auto-track page views. You call them yourself with oaiq("measure", ...). The simplest version, fired on every page load:

oaiq("measure", "page_viewed", {
 type: "contents",
 contents: [
   { id: "pricing", name: "Pricing page", content_type: "page" }
 ]
});

This alone gives OpenAI enough to attribute traffic from ad clicks. For most accounts, page views and one or two conversion events are enough to launch on.

Step 3: add the events that matter for your business

Beyond page views, send events that map to actions you actually care about. OpenAI provides a fixed taxonomy of standard event names, each with a defined data shape. The full list:

Pick the ones that match your funnel. Full data shapes and required fields are in OpenAI's supported events documentation.

For ecommerce, the order created event is the one that matters most:

oaiq("measure", "order_created", {
 type: "contents",
 amount: 2599,
 currency: "USD",
 contents: [
   { id: "sku_123", name: "Starter bundle", content_type: "product", quantity: 1 }
 ]
}, {
 event_id: "order_12345"
});

A few rules to follow. Use integer values for amount (in the currency's lowest denomination, so 2599 means £25.99) and quantity. Stick to the documented fields inside contents[]. Pass an event_id you can reproduce later, you will need it for deduplication once the server-side leg goes in.

For lead generation businesses, the typical pair is lead_created and registration_completed, both with the simpler customer_action shape:

oaiq("measure", "lead_created", {
 type: "customer_action"
});

For subscription businesses, subscription_created and trial_started use a plan_enrollment shape:

oaiq("measure", "subscription_created", {
 type: "plan_enrollment",
 plan_id: "pro_monthly",
 amount: 2000,
 currency: "USD"
});

If you need something OpenAI does not have a standard name for, use custom. Keep eventName as custom, set type to custom, and put your event label in eventOptions.custom_event_name.

Step 4: add the Conversions API for the conversions the pixel will miss

The pixel cannot escape the browser. Ad blockers, Safari ITP, consent denial, and dropped sessions all eat conversions. If a user buys two days later in a different session with cookies cleared, the pixel will not see it.

The Conversions API closes that gap. It is a server-to-server endpoint at https://bzr.openai.com/v1/events, authenticated with a bearer token from your Ads Manager. You POST event batches of up to 1,000 events at a time, and OpenAI's own documentation says it plainly: the Conversions API is a more reliable source than the pixel alone, and they recommend using it where possible.

The accuracy gain is real. Server events are not blocked by extensions, do not depend on the user's browser executing JavaScript, and can be enriched with data the browser never sees, such as backend order states, refund flags, lead qualification, or CRM identifiers.

One catch. The API will not capture oppref for you. Read it from the __oppref cookie or the landing URL on the client, pass it to your server with the rest of the order data, and include it on the server event payload.

Step 5: deduplicate browser and server events

If you fire the same conversion from both the pixel and the Conversions API, OpenAI needs to know it is one event, not two. Send the same identifier as event_id on the pixel and id on the API call, against the same Pixel ID. For custom events, keep custom_event_name consistent across both. OpenAI matches on Pixel ID, event name, and event_id. Mismatched IDs mean duplicates, and duplicates inflate reported conversions.

Doing it through GTM

If you would rather not maintain the snippet and the API call directly, server-side Google Tag Manager handles both. We partner with Stape, who have built community templates for each side: an OpenAI Ads pixel tag for web GTM and a matching OpenAI Conversions API tag for server GTM. Both support GA4 event mapping, GTM consent mode, and a shared event ID variable so deduplication works without custom code.

If you do not have a server-side GTM container yet, ChatGPT ads are a reasonable trigger to set one up. The same infrastructure handles Meta CAPI, Google Ads enhanced conversions, TikTok Events API, and now OpenAI. We have a write-up of how server-side GTM works on our server-side tracking page.

What to do next

Get the pixel live first with a page view event. It takes an afternoon and unblocks campaign optimisation while you plan the rest. Add your one or two key conversion events next, then schedule the Conversions API work as a follow-up, ideally on the same server-side container that already handles your other paid channels.

If you want help with any of it, including the server-side GTM build or the Stape configuration, get in touch.