EN DE
Get a Free Audit

ChatGPT Ads Conversions API: Server-Side GTM Setup

Step-by-step guide to the ChatGPT Ads Conversions API in server-side GTM: endpoint, event mapping, oppref capture, dedup by id, and consent gating.

How to Set Up the ChatGPT Ads Conversions API in Server-Side Google Tag Manager

A browser tracking pixel is a snitch that often gets caught at the door. Ad blockers, Safari’s tracking prevention, and privacy settings stop it from reporting back, so a chunk of your real conversions never reach ChatGPT Ads. The Conversions API fixes that by sending the conversion from your own server, where no browser extension can block it. This guide walks you through wiring the ChatGPT Ads Conversions API into server-side Google Tag Manager, step by step, in plain language.

Key Takeaways

  • Server-side sends conversions from your server, not the browser – it survives ad blockers and tracking prevention that practitioners say cost browser pixels roughly 20-30% of conversions (Focal estimate)
  • The endpoint is one POST requestPOST https://bzr.openai.com/v1/events?pid=<PIXEL-ID> with a Bearer token, both from the conversions tab in Ads Manager (per OpenAI's Conversions API docs)
  • The Conversions API does NOT auto-capture oppref – you must grab ChatGPT's click identifier yourself and pass it on the event, or your server conversions go unattributed
  • Deduplicate by reusing the same id on the pixel and the API event, or you double-count and corrupt your bidding

This is the deep technical build. For the strategy layer (UTM structure, view-through, cross-channel credit) see our ChatGPT Ads attribution guide, and for the general server-side foundations that apply to every platform, see our server-side GTM tracking guide.

One honesty note first. ChatGPT Ads is live to advertisers only in the US, UK, Australia, New Zealand and Canada as of 2026-06-13. It is not bookable for EU or DACH advertisers yet. So this setup is something you run today if you are a US/UK/CA/AU/NZ entity, or build now so your measurement is ready the day OpenAI opens the EU. Either way, the work below is real and writable today.

Why Server-Side for ChatGPT Ads

Think of conversion tracking like delivering a receipt back to the advertising platform that says “this person you sent me actually bought something.” There are two ways to deliver that receipt.

The first is the browser pixel: a small piece of JavaScript that fires from the visitor’s browser. The pixel for ChatGPT Ads loads from bzrcdn.openai.com/sdk/oaiq.min.js and runs through a function called oaiq() (per OpenAI’s measurement pixel docs). It works, but it lives in the browser, which means it can be blocked. Practitioners at Focal estimate browser pixels alone lose roughly 20-30% of conversions to ad blockers and tracking prevention. Treat that as a practitioner estimate, not an official OpenAI number.

The second is the Conversions API (often shortened to CAPI). Instead of asking the browser to send the receipt, your own server sends it directly to OpenAI. No browser, no extension, no blocker in the way. Practitioners at Lapis report that adding the Conversions API alongside the pixel typically recovers 15-25% more tracked conversions. Again, a practitioner estimate, not an OpenAI figure.

The strongest setup is both, deduplicated: pixel for speed and rich browser context, Conversions API for completeness and reliability, with a shared ID so the same conversion is never counted twice. That hybrid model is what the rest of this guide builds.

Why this matters beyond a clean dashboard. OpenAI activated CPA bidding (conversion-optimized campaigns) for the US self-serve beta on 2026-06-05 (per PPC.land). Conversion-optimized bidding needs a steady, accurate conversion signal to learn from. If your tracking under-reports or double-counts, the algorithm learns from bad data. Getting the Conversions API right is not a reporting nicety, it is a bidding prerequisite.

What You Need Before You Start

Gather these four things first. The build goes smoothly when they are ready and painfully when they are not.

  1. A ChatGPT Ads pixel ID. This is your account’s tracking ID. You find it in the conversions tab inside Ads Manager. It looks like a short code and goes into the endpoint URL.
  2. A Conversions API key (Bearer token). Also provisioned from the conversions tab. This is the password that proves the events are really coming from you. Treat it like a password: it lives on your server, never in browser code.
  3. A server-side GTM container. This is a Google Tag Manager container that runs on a server you control (commonly hosted via Stape or TAGGRS) rather than in the visitor’s browser. If you have never set one up, start with our server-side GTM tracking guide, then come back here.
  4. A web GTM container that already fires your conversion events. Your form submissions, bookings, and purchases need to already trigger events (for example a dataLayer push) that the server container can receive.
Keep the API key off the browser. The Bearer token authenticates server requests. If it ever appears in client-side code or a public repository, anyone can send fake conversions to your account. Store it only in server-side GTM (as a server container variable or environment value), never in a web container tag.

The Conversions API Endpoint and Auth

Everything the Conversions API does is one HTTP POST request. Here is the shape of it.

  • Method and URL: POST https://bzr.openai.com/v1/events?pid=<PIXEL-ID> (replace <PIXEL-ID> with your pixel ID).
  • Authentication: a Bearer token in the request header, the API key from your conversions tab. In plain terms, you attach a header that reads Authorization: Bearer <your-api-key>.
  • Body: a JSON payload containing your event or a batch of events.

That is the whole transport. The detail that makes or breaks accuracy is what goes inside the event.

Required Event Fields

Every event you send needs these fields (per OpenAI’s Conversions API docs):

FieldWhat it isRule that trips people up
idA unique ID for this conversionThis is also your deduplication key. Reuse the exact same value on the pixel.
typeThe event type (for example lead_created)For a custom event, set type to custom and add custom_event_name.
timestamp_msWhen the conversion happened, in millisecondsMust be within the last 7 days, and no more than 10 minutes in the future.
dataEvent details (value, currency, oppref, and so on)This is where you attach oppref and enhanced matching.

The timestamp_ms rule matters for offline conversions. If a sales rep marks a lead as qualified in your CRM five days after the form fill, you can still send it, because five days is within the 7-day window. Eight days late, and the event is rejected. Build your CRM sync to fire well inside that window.

Batching

You can send up to 1,000 events in a single batch instead of one request per event. There is one rule to respect (per OpenAI’s docs): if a single event in the batch fails, the whole batch fails. So one malformed event can sink 999 good ones. Validate each event before you batch, and keep batches modest so a failure is easy to isolate and resend.


Capturing and Passing oppref Server-Side

This is the single most common thing people get wrong, so slow down here.

oppref is ChatGPT Ads’ click identifier. It is the same idea as the gclid that Google adds to a link or the fbclid that Meta adds: a tag on the landing-page URL that lets the platform connect a click to the sale that follows. When someone clicks your ChatGPT ad, OpenAI appends oppref to your landing URL.

The browser pixel handles oppref for you: it reads oppref from the URL and saves it into a first-party cookie named __oppref (reported as roughly a 30-day lifetime by practitioner sources) so it persists across page views. Easy.

The Conversions API does not do this. Per OpenAI’s docs, CAPI does not auto-capture oppref. If you skip this step, your server-side conversions arrive with no click identifier and ChatGPT Ads cannot tie them back to the click that earned them. They are effectively invisible to the channel.

So you have to capture and pass oppref yourself. The flow is three short hops:

  1. Read oppref from the landing URL the first time the visitor arrives, using your web GTM container.
  2. Store it in a first-party cookie (the same __oppref cookie the pixel uses, or your own) so it survives the gap between the click and the eventual conversion.
  3. Read that cookie at conversion time and include oppref inside the data object of the Conversions API event you send from the server.
The two ways people lose oppref. First, redirects: if your landing page bounces through a redirect that strips query parameters, oppref is gone before the cookie is ever set. Test your real ad URL end to end, including any redirect. Second, not persisting it: if you read oppref but never write the cookie, it vanishes on the next page view and any later or offline conversion has nothing to attach.

Deduplication Between Pixel and CAPI

If you run both the pixel and the Conversions API, the same conversion can be reported twice: once by the browser, once by your server. Double-counted conversions inflate your numbers and, worse, feed garbage to CPA bidding.

OpenAI’s fix is simple and you control it (per OpenAI’s docs): reuse the same value as the API id and the pixel event_id for the same conversion. When OpenAI receives two events with the same ID, it discards the duplicate. Server-side data is typically the one kept. For custom events, match on custom_event_name across both channels too.

The practical pattern:

  1. When a conversion happens, generate one unique ID (for example a UUID, or your order or lead reference).
  2. Pass it to the pixel as event_id.
  3. Pass the exact same value to the Conversions API as id.

The hard part is making both halves see the same ID. The Stape open-source tags include a unique-event-ID variable built specifically for this web-plus-server deduplication, which saves you from hand-rolling it.

Symptom and cure. If your reported conversions look suspiciously high, or higher than what GA4 and your CRM show, mismatched IDs are the usual cause. The cure is always the same: confirm that the ID the browser sends and the ID the server sends are byte-for-byte identical for one and the same conversion.

Enhanced Matching With SHA-256 Hashes

Enhanced matching helps OpenAI connect a conversion to the right click even when the basic signals are thin. You do it by adding an optional user object to the event (per OpenAI’s docs).

That user object accepts hashed customer identifiers such as email or an external ID, plus raw geographic, IP address, and user-agent values. The identifiers like email must be hashed with SHA-256 and sent as a lowercase 64-character hex string.

In plain terms, hashing is a one-way scramble. You never send the real email address. You run it through SHA-256 and send the scrambled output. OpenAI hashes its own data the same way and compares the scrambles, so a match can happen without the raw email ever leaving your server.

Two rules keep this clean and compliant:

  • Normalize before you hash. Lowercase the value and trim spaces first, so [email protected] and [email protected] produce the same hash.
  • Never send raw personal data. The whole point is that the raw email or phone number never travels. Send only the hash. Server-side GTM is the right place to hash, because it happens on your infrastructure, not in the visitor’s browser.

Using the Stape and TAGGRS Open-Source Tags

You do not have to build all of this from scratch. Two open-source toolsets already exist for server-side GTM.

ToolingWhat it gives youWhere it runs
StapeAn openai-pixel-tag (web) and an openai-capi-tag (server-side), plus a unique-event-ID variable for web-plus-server deduplicationGTM web + server
TAGGRSAn Apache-2.0 licensed sGTM tag that captures the oppref query parameter into a first-party cookie, sends standard and custom events, and transmits hashed Email/Phone for enhanced matchingGTM server-side

These tags handle the fiddly parts (the endpoint call, the oppref cookie, the hashing, the dedup variable) so you can focus on mapping your own events correctly. Import the tag template into your server container, point it at your pixel ID and API key, and wire it to the events your web container already sends. Read the tag’s own documentation for the exact field names, because they may change as the maintainers update them.

The payoff of doing this once, properly. A correctly deduplicated pixel-plus-CAPI setup with oppref captured server-side gives ChatGPT Ads a complete, accurate conversion signal: the part the browser can report, plus the part it loses, with no double counting. That is exactly the signal CPA bidding needs to optimize, and exactly the proof you need to decide whether the channel earns more budget.

Mapping Standard Events to a Lead-Gen Plan

ChatGPT Ads ships with standard event names so you do not have to invent your own. The lead-generation ones are lead_created, registration_completed, and appointment_scheduled (per OpenAI’s measurement pixel docs). There is also order_created for ecommerce, and you can define custom events with type: custom plus a custom_event_name.

Map your real funnel to those names. Here is a typical lead-gen mapping.

Your funnel stepStandard event to sendWhen it fires
Contact or quote form submittedlead_createdOn the form thank-you action
Free account or trial signupregistration_completedOn signup confirmation
Calendly or demo call bookedappointment_scheduledOn the booking confirmation
Offline: lead marked qualified in CRMlead_created (custom value) or a custom eventWhen your CRM sync runs, within the 7-day window

For each one, send the event from your server with: a unique id (also used as the pixel event_id for dedup), the correct type, a timestamp_ms inside the 7-day window, the captured oppref inside data, and an optional hashed user object for enhanced matching. That single recipe covers every row in the table.

If you want the full lead-generation strategy around this (which events to treat as primary, how to structure the account so the data is clean), our Google Ads account structure for lead gen covers the structural thinking that carries straight over to ChatGPT Ads.


If you serve EU or DACH visitors, consent comes before tracking, not after. OpenAI’s published EU ads policy is consent-first: explicit opt-in, with consent (not legitimate interest) as the legal basis (per Digiday, as of 2026-06-08).

The official pixel docs do not document native consent-mode support, so practitioners wire it up themselves. The common pattern (per Stape) is to gate the pixel on Google Consent Mode: when ad_storage consent is denied, the tag does not load the oaiq SDK and no events fire. With a manual install you wrap the init in a consent check yourself.

Server-side is your friend here, because the hashing and the consent logic both live on infrastructure you control rather than in the visitor’s browser. That said, server-side does not exempt you from consent: you still need a lawful basis to process the data at all.

Server-side is not a consent loophole. Sending a conversion from your server instead of the browser changes where the request originates, not whether you needed permission to process the person's data. In the EU, capture valid consent first, then let consent state govern whether your server fires the event. Do not treat CAPI as a way around the consent prompt.

Because ChatGPT Ads is not yet bookable in the EU or DACH, this section is about building correctly now so you launch compliant on day one. If you want this done for you, our tracking and measurement service builds consent-gated, server-side stacks for exactly this situation, and our ChatGPT Ads service covers the campaign side once the market opens.


Frequently Asked Questions

ChatGPT ads are here, but can we measure their performance?

Yes, and that is precisely what this setup does. The native dashboard alone reports only impressions, clicks, spend and CTR (per Focal), with no conversion attribution or ROAS. To measure performance you install the pixel and the Conversions API, capture oppref, and send your conversion events. Once that signal flows, you can see which conversions came from ChatGPT Ads and feed CPA bidding. The headache people describe in r/PPC is real, but it comes from running on the bare dashboard rather than from a missing capability.

Do I need server-side, or is the pixel enough?

The pixel alone works but under-reports, because browser pixels lose conversions to ad blockers and tracking prevention (practitioners at Focal estimate 20-30%). Server-side recovers a chunk of that and is more reliable for offline and CRM events. If you run any meaningful budget, or you rely on CPA bidding, run both deduplicated. If your budget is tiny and you only have simple on-site conversions, the pixel alone can be a reasonable starting point you upgrade later.

Why are my conversions double-counted in ChatGPT Ads?

Almost always because the pixel and the Conversions API are sending the same conversion with different IDs, so OpenAI sees them as two separate events. The fix is deduplication: use the exact same value for the pixel event_id and the API id for one and the same conversion. When the IDs match, OpenAI discards the duplicate and keeps one (usually the server-side one).

Does the Conversions API capture oppref automatically?

No. Per OpenAI's docs, the browser pixel auto-captures oppref into the __oppref first-party cookie, but the Conversions API does not. You must read oppref from the landing URL, store it in a first-party cookie, then attach it to the data object of each server event. Skip this and your server-side conversions arrive with no click identifier and cannot be attributed to ChatGPT Ads.

How fresh does the timestamp need to be?

The timestamp_ms on each event must be within the last 7 days and no more than 10 minutes in the future (per OpenAI's docs). For on-site conversions this is automatic. For offline or CRM-driven conversions, make sure your sync fires inside the 7-day window, otherwise OpenAI rejects the event.


Get the Signal Right Before You Scale Spend

The Conversions API is not exotic. It is one POST request, a handful of required fields, a captured oppref, a shared ID for deduplication, and hashed identifiers for matching. Get those five things right and ChatGPT Ads finally sees the conversions the browser was losing, which is the difference between guessing at performance and knowing it.

The order to build in: confirm you can read and persist oppref, send a single test event and watch it land, add the pixel with a matching event_id for dedup, then layer in enhanced matching and your full event map. Once it is solid, CPA bidding has a clean signal to optimize against.

If you would rather have this implemented and validated for you, that is our work. See our tracking and measurement service for the server-side build, our ChatGPT Ads service for the campaign side, or book a free audit to find the gaps in your current setup.

Sources & References

18 points
Free Download

ChatGPT Ads Measurement Readiness Checklist

A pre-launch readiness check for measuring ChatGPT Ads server-side. 18 points covering pixel and Conversions API setup, consent-gated loading, deduplication, and event mapping.

Need help with your performance marketing?

Book a free consultation and let's discuss your goals.