Ridoway
🔥 Extra 20% OFF HostingerGet Extra 20% Off →
GuidesSeptember 14, 202612 min read
Written by Mominul Islam·Reviewed by Ridoway Ads Team·Last verified: September 2026

What Is ChatGPT Pixel Helper? How to Verify Your ChatGPT Ads Pixel

“ChatGPT Pixel Helper” sounds like one tool. It is really four things stacked on top of each other: OpenAI's measurement SDK, the pixel ID you create in Ads Manager, the server-side Conversions API that mirrors events from the backend, and a browser extension that inspects all of it. They fail in different ways, at different layers, and none of them prints an error to the screen. This guide sets the vocabulary, shows you the exact install snippet OpenAI documents, and gives you a verification checklist that takes ten minutes on any live site — before you spend a dollar on impressions.

Sources: OpenAI \u2014 Measurement Pixel docs ↗ · Conversions API docs ↗ · Supported events ↗

The Three Layers, at a Glance

Before the details, the mental model. Every thing people call by the name “pixel” in this ecosystem is one of these:

LayerWhat it isWhere it lives
Measurement PixelThe browser SDK (global name oaiq) that observes events and pings OpenAI.Your site's HTML <head>
Conversions APIServer-side HTTP endpoint at bzr.openai.com/v1/events for events that never reach a browser.Your backend, never page code
Pixel HelperA browser extension that inspects the SDK and flags broken payloads as they fire.Your browser, as a debugging view

The naming collision is the source of most confusion. When someone says “my pixel is not working,” ninety percent of the time the pixel is installed, initializing, and firing — and the payload or the page it fires on is wrong. That is precisely what a pixel helper exists to surface.

What “Pixel Helper” Actually Means

A Pixel Helper is the layered debugging view of a tag-management-era idea: you put one script on the page, and a browser extension tells you whether that script is doing what it claims. For ChatGPT Ads, the script is OpenAI's measurement SDK and the questions the helper answers are the ones Google Tag Assistant and Meta's Pixel Helper used to answer before it.

Concretely, a helper watches the page for three things:

  • Whether the SDK is present and initialized. You should see exactly one init, with the correct pixel ID.
  • Every oaiq("measure", ...) call as it happens — the event name, the data shape, the event_id, and whether the payload matches what OpenAI documents.
  • Warnings that Ads Manager will accept silently. Float amounts, missing currency, undefined content fields, event names with spaces — all of these are legal JavaScript that OpenAI’s API tolerates and your reporting quietly forgets.

Our version is the ChatGPT Pixel Helper by Ridoway extension, available for Chrome and Edge from the Chrome Web Store and for Firefox from AMO. There is also a free, no-install version of the check: point the ChatGPT Ads Pixel Checkerat any URL and it tells you whether that URL carries the pixel at all. The extension answers “is it working right now?”. The checker answers “is it even installed on this page?”. You want both.

Anatomy of the Pixel: Install, Init, Measure

The current official snippet, from OpenAI's measurement pixel documentation, is a guarded loader followed by an init call. Put it in the <head> near the top of every page where conversions might happen:

<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: "pId_XXXX",
  });
</script>

Three details in that snippet matter more than the rest. The if (w.oaiq) return guard keeps the SDK from loading twice if the snippet is pasted twice. The pixel ID comes from the conversions tab of Ads Manager, begins with pId_, and is the single value most people copy wrong. And debug: true can be added to the init options to log SDK activity to the console while you test.

Then you measure. A oaiq("measure", ...) call takes up to four arguments: the command, the event name, the event data, and an options object. The event data always selects a shape with a type field: contents for commerce and content, customer_action for leads and registrations, plan_enrollment for subscriptions, and custom for everything else. A purchase event, exactly as OpenAI documents it:

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

Note what is not in that call: no user PII, no timestamp, no URL. The SDK handles transport automatically. It captures oppref from the landing page URL (a privacy-preserving identifier Google campaign-style), stores it in a first-party __oppref cookie so later pages reuse it, adds the page origin as source_url, timestamps each event, and batches closely grouped measure calls. With automatic advanced matching enabled it also hashes customer info in the browser before it leaves.

Two transport facts worth keeping in your back pocket for the troubleshooting section. First, events are sent to bzr.openai.com (connect-src), while the SDK itself loads from bzrcdn.openai.com (script-src) — a strict Content-Security-Policy needs both, plus img-src bzr.openai.com for the image-request fallback. Second, the measurement pixel does not support app_installed or app_opened; those are Conversions API events only, sent with action_source: mobile_app.

The standard event names are deliberately boring lowercase snake_case, and that is a feature: page_viewed is not pageViewed, order_created, lead_created, registration_completed, checkout_started, trial_started, and so on. If your pixels fire camelCase versions, Ads Manager treats them as unknown and your goals stay silent. When a standard name genuinely does not fit, use a custom event instead:

oaiq("measure", "custom", { type: "custom" }, { custom_event_name: "quote_requested" })

The custom name has real constraints: 1\u201364 characters, only letters, numbers, underscores, or dashes, starting and ending with a letter or number — and it must not match a standard event name.

What a Working Pixel Looks Like

A working setup is not a single event. It is a habit across every relevant page. On a purchase site, the healthy sequence reads like a script:

  • Every page: page_viewed fires once per load, carrying the __oppref cookie if it exists.
  • Product page: contents_viewed with the item id, name, and content_type product.
  • Add to cart: items_added with amount, currency, and the line item.
  • Checkout: checkout_started with the running total.
  • Thank-you page only: order_created with the final amount, plus an event_id that the server-side call reuses.

Attribution then works on a windowed model, and the details decide what your dashboard shows. Click-through conversions use whatever click window is configured on the account. View-through conversions use a fixed one-day window after an eligible impression, and when a conversion is eligible for both, click wins — so the number you see in Conversions is click-through only. View-through appears as a separate campaign-level metric and is excluded from Conversions, CPA, and bidding.

That last clause explains a startling number of “pixel not working” reports. The pixel could be flawless and the Conversions column could still lag for hours — attribution is asynchronous — and view-through credit the pixel generated would never appear in that column by design.

The Verification Checklist (Step by Step)

Run this on a staging page first, then on production after any template or tag change. It assumes the pixel is already installed.

Step 1 \u2014 Confirm the SDK loads

Open any page in Chrome or Edge and press F12 to open DevTools. Go to the Network tab and filter for oaiq. You should see the SDK file load from bzrcdn.openai.com/sdk/oaiq.min.js, followed by a small configuration request and, on subsequent pages, event pings to bzr.openai.com. No SDK request at all is a loading problem \u2014 a blocker, a misconfigured CSP, or the snippet never made it into the page template.

Step 2 \u2014 Confirm exactly one init with the right pixel ID

In the same Network view, or with debug: true enabled, you should see init once, holding the pId_ value from Ads Manager. Two inits means the snippet was pasted twice or injected both by the theme and a plugin; the if (w.oaiq) return guard exists precisely to stop this, so if your site still double-inits, check for two separate copies not sharing the guard. A wrong pixel ID means the events will be recorded against a different pixel than the one your campaigns measure.

Step 3 \u2014 Confirm events fire on the right pages

The most common structural bug in the whole ecosystem: a conversion event wired to the page load of the page where the form is viewed, or to “all pages,” instead of the confirmation page after the action completes. Walk the funnel manually — home, product, cart, checkout, then place a test order to the thank-you page. You should see page_viewed everywhere and the conversion event only at the end. Buyers who stop at checkout also need checkout_started to fire, or you will never learn where the funnel breaks.

Step 4 \u2014 Validate the payloads

For each event, check the details against OpenAI's rules, because none of these produce a hard error:

  • amount and quantity are integers (2599), never floats (25.99) or strings ("25.99").
  • currency is present wherever amount is present, and it is a three-letter ISO code.
  • Only documented fields appear inside contents[] — id, group_id, name, content_type, quantity, amount, currency, variant_dict.
  • Standard events use standard snake_case names; custom events have a valid custom_event_name and carry no standard-name collision.
  • Event data type (contents / customer_action / plan_enrollment / custom) matches the event being measured.

Step 5 \u2014 Confirm event_id and deduplication

If the same conversion also goes through the Conversations API server-side, the browser event and the server event must reuse the same event_id. Deduplication matches on pixel ID + event name + event_id (custom events match on pixel ID + custom_event_name + event_id), and OpenAI keeps the first event it receives for a key. Without a shared event_id, order_created fires twice and your reporting double-counts every order. Generate the ID yourself \u2014 an order number or a UUID \u2014 and pass the same value to both layers.

Step 6 \u2014 Check attribution context

From a normal (non-cognito) tab, run a dummy ad link containing oppref in the landing URL, land on the page, and confirm the __oppreffirst-party cookie is written in Application → Cookies. This is the identifier that ties a conversion back to a click. If it never appears, the pixel stores nothing to attribute against and everything works except the part that matters.

Step 7 \u2014 Verify the server side separately

Browser testing proves nothing about the Conversions API. Check your server logs for POST /v1/events?pid=<PIXEL_ID> returning 200, and use validate_only in development to check payload acceptance without recording. Never run this call from page code \u2014 the endpoint expects an access token, and the SDK lacks one by design.

The Three-Minute Version

Short on patience? This catches the majority of real failures:

1Open your site with the ChatGPT Pixel Helper extension enabled. The badge should turn green within seconds.
2Click the badge and confirm one init row with the right pId_ value.
3Trigger your conversion: place a test order or submit the form. Watch the measure row appear on the thank-you page, not before.
4If any row shows a warning, fix the flagged field \u2014 it is either a float amount, a missing currency, an invalid event name, or a field OpenAI never documented.
5Still paid same-day: if events fire and warnings are empty but Ads Manager shows nothing, that is attribution delay and goal configuration, not your pixel.

Using the ChatGPT Pixel Helper Extension

Install the free ChatGPT Pixel Helper by Ridowayfrom the Chrome Web Store (or AMO on Firefox) and pin it to your toolbar. Visit any page and the badge shows whether OpenAI's pixel is detected on that page; while a session is active it also reports how many events have fired. Click the badge to open the live log.

Each log row is one SDK call: the init row with the pixel ID, then one row per measure event with the event name, the data type, any event_id, and a status. Rows the SDK itself would accept silently get flagged. That is the entire point: OpenAI's endpoint is lenient about a lot of wrongness, and painlessly lenient integrations are how marketing teams spend six weeks believing an event was tracked.

Two siblings to this tool are worth knowing. The ChatGPT Ads Pixel Checker scans a URL without opening a browser and tells you whether the pixel exists in its HTML \u2014 useful for auditing pages you do not control. The Pixel Event Debugger normalizes and validates a raw payload offline, which is what devs want when they are diffing values against a staging environment.

Troubleshooting Table: What Each Symptom Means

SymptomCauseFix
No SDK request in NetworkSnippet absent, ad blocker, or CSP blocks script-src bzrcdn.openai.comAdd the snippet to the page template, not a post; whitelist the CDN in CSP.
Init fires twiceTwo copies of the snippet without the shared guardKeep the guarded loader; remove the second inline copy.
Events fire on load of the form page, not the thank-you pageConversion event wired to “all pages” or page-view triggerMove the measure call to the confirmation page or a completion event.
No events on a SPA route changeSingle-page apps never reload the headRe-run init (and page_viewed) on each route change in your framework router.
Conversions double-countedBrowser and server events send different event_id values (or none)Generate one event_id, reuse it on the pixel and the Conversions API call.
Events fire, Ads Manager shows nothingNo custom conversion or goal wired to the event; attribution delay; view-through not in ConversionsCreate the conversion in Ads Manager, then wait a day before judging.
No pings after a consent banner interactionconsent false is blocking events by designCall oaiq("consent", true) when the user grants; blocked events do not replay.
Payloads work in the helper but look wrong in a validatorFloat amounts, missing currency, undocumented contents[] fieldsUse integer minor units, always pair amount with currency, keep only documented fields.

Five Mistakes That Make a Pixel Look Broken

  • Duplicate init. The SDK is loaded twice, injures the attribution baseline, and makes every event fire twice. Symptom: two initialization rows.
  • The wrong pixel ID. Copied from an old account, from a colleague, or from a screenshot. Symptom: events fire cleanly and the Conversions column stays empty.
  • Conversion events on the wrong page. Firing order_created on page load of a product page reports a purchase that never happened and drowns the real signal.
  • Float and string amounts. 25.99 instead of 2599. Ads Manager accepts it, and your revenue totals come out in cents or worse, silently.
  • Calling the Conversions API from the browser. The endpoint needs an access token that cannot live in page code. Symptom: either 401s all day or a leaked secret.

Every one of these is invisible in the browser and everywhere in your reporting. That combination — silent acceptance on the front end, silent wrongness in the metrics — is why a pixel helper exists at all.

On WordPress, Skip All of It

If your site runs WordPress, none of the snippet surgery above is necessary. The free Ridoway Pixel plugin installs the browser pixel across the whole site, sends the money events server-side through the Conversions API (keeping the access token on the server where it belongs), and handles event_iddeduplication between the two layers. It already does the field validation this article walks through by hand — integers, currency pairing, documented event names — so the payload-validity failures are prevented rather than discovered.

On any other stack, the integration wizard generates the correct snippet and server-call code for your framework, and the conversion tracking guide walks the whole setup in more depth than this one.

Frequently Asked Questions

What is the ChatGPT Pixel Helper?

The ChatGPT Pixel Helper is a browser extension that inspects the ChatGPT Ads measurement pixel on whatever page you visit. It watches for the oaiq SDK, records every init and measure call as it fires, and flags malformed payloads (float amounts, missing currency, invalid event names) that Ads Manager would otherwise accept silently. It does not install a pixel for you and it does not collect data itself.

Is the ChatGPT Pixel Helper the same as the measurement pixel?

No. The measurement pixel is OpenAI's browser SDK: a small script loaded from bzrcdn.openai.com/sdk/oaiq.min.js that you initialize with a Pixel ID and call oaiq("measure", ...) on. The Pixel Helper is a separate debugging tool that reads what that SDK is doing. You install the SDK to track conversions; you use an inspector like Pixel Helper to confirm the SDK is behaving.

Does the measurement pixel slow down my site?

Negligibly. The SDK loads asynchronously from a CDN, sends events as small batched requests (fetch or sendBeacon), and stores a single first-party cookie (__oppref). It is a debugging tool that sits in the browser, not a heavyweight tag manager. What slows a site down is shipping thirty tag-manager containers on top of one another; one measurement SDK is not that.

The helper shows events firing, but Ads Manager reports no conversions. Why?

Four common causes. First, no custom conversion has been configured from your events in Ads Manager — events are tracked, but nothing counts them as a conversion metric. Second, attribution is delayed: dashboard numbers trail live delivery by hours, and view-through conversions use a fixed one-day window and are reported as a separate metric, never inside Conversions. Third, the conversion was eligible for both click-through and view-through, and the click took precedence, so it counts once. Fourth, the events being sent are not standard event names, so Ads Manager cannot map them to goals that exist in its reporting.

Does event_id really matter?

Yes, if you send events from both the browser pixel and a server-side integration. Duplicate-event matching uses your Pixel ID, the event name, and the event_id: OpenAI keeps the first event it receives for a matching key and ignores later duplicates. Generate the event_id yourself and reuse the exact same value on the browser and server call, and the same conversion will never double-count.

Do I need both the pixel and the Conversions API?

It depends how much you trust the browser. The pixel captures everything that happens in the browser: page views, added items, checkouts. The Conversions API sends the same categories of events server-side, which survives ad blockers, brute-force sessions, and users who never complete the page. Run both for the events that matter most and deduplicate with event_id. Also note the pixel does not support app_installed or app_opened — those are Conversations API events only, with action_source mobile_app.

How do I verify server-side (Conversions API) events?

Check your server logs for POST requests to bzr.openai.com/v1/events?pid=<YOUR-PIXEL-ID> returning 200. In development you can add validate_only to the request to check payload acceptance without recording events. The critical rule: never call the Conversions API directly from page code. The endpoint expects an access token that would be exposed in the browser, and OpenAI explicitly instructs integrations to call it from the server. On WordPress, the free Ridoway Pixel plugin handles the server call and hides the token.

Does the pixel require consent for privacy regulations?

The SDK defaults consent to true but lets you control it: call oaiq("consent", false) before init to disable all measurement pings until the user grants consent, then oaiq("consent", true) afterward. Blocked events are never replayed. Identifiers are SHA-256 hashed in the browser before anything leaves it (automatic advanced matching), and the __oppref identifier is privacy-preserving and first-party. If your site enforces GDPR or similar, wire the consent call to your existing consent banner.

Verify your pixel the fast way

Install the free ChatGPT Pixel Helper extension, scan your site with the URL checker, and stop trusting a silent pixel.

Keep reading