Are you spending on ChatGPT Ads without knowing which leads or orders they produced? OpenAI’s Ads Manager gives you two ways to send it conversions: a browser pixel and a Conversions API. Use only the pixel and you lose conversions to ad blockers, browser extensions and Apples tracking protection. Use both without matching them up and OpenAI counts every conversion twice, which makes your cost per lead look half what it really is.
This guide shows the full setup we tested end to end on our own site: the OpenAI Ads Pixel in web Google Tag Manager, the OpenAI Conversions API in server-side GTM (sGTM) hosted on Stape, and the Event ID that ties the two together so each conversion is counted once. It also covers the two problems that stopped our first attempt working, because you will probably hit at least one of them.
The video walks through every screen. The written steps below match it, so you can follow either. There’s also a free PDF checklist at the end of this post that covers every setting in order, with space to record the values you used. Jump to the download.
What we're building
We’re going to track a website lead in ChatGPT Ads using both:
- the OpenAI Ads Pixel in web GTM
- the OpenAI Conversions API in server GTM
We’re using the Stape templates for both.
Our website already pushes a generate_lead event into the data layer when somebody successfully submits the contact form. We’re going to use that as an example of how to turn it into OpenAI’s standard lead_created event.
Using the Pixel and the Conversions API together gives OpenAI two ways of receiving the conversion. The important part is giving both versions the same Event ID, so OpenAI knows they’re the same conversion rather than two separate leads.
If you’re an ecommerce site, the process is the same. Swap generate_lead for your purchase event and lead_created for OpenAI’s order_created, and read the ecommerce notes in each step.
Before you start: check the event you already have
Before setting anything up in OpenAI, establish what you’re going to track.
In our example, a successful form submission creates:
event: generate_lead
value: 1136
currency: GBP
lead_id: 1748
lead_type: contact
form_id: 18784
user_data.email_address: [email protected]You don’t need these exact parameters. What matters is a reliable event that only fires when the conversion has actually happened.
For an ecommerce website, you’d normally start with existing ecommerce events such as purchase, add_to_cart or their equivalents.
Step 1: Set up OpenAI Ads Manager
Create the OpenAI Data Source
Set up a OpenAI Ads Manager account here: https://ads.openai.com/ or login if you already have account. To set up tracking, you will first need to add a logo and add payment details to the account.
Once you have set up your account, go to the left-hand menu and select Tools then Conversions and start on the Data Source tab.
Create a new Web Data Source. Call it something like Website Name Pixel Data Source. We called ours Conversion Uplift Data Source.
Once it’s created, OpenAI gives you a Pixel ID. Copy it, because the same Pixel ID goes into both web GTM and server GTM.
Don't confuse the two OpenAI objects
A Data Source identifies the website or integration fo sending the data.
A Conversion Event defines the action you’re interested in, such as a lead or a purchase. That’s next.
Create the Conversion Event
Go to Tools then Conversions then Conversion Events and create a new conversion event.
For our contact form we used:
- Display name: Lead Created
- Event type: Standard
- Standard event:
lead_created
Associate it with the Web Data Source you just created.
For an ecommerce implementation, choose the standard event that describes the action you’re measuring. These include order_created, subscription_created and registration_completed.
For e-commerce sites, OpenAI recommend implementing five standard events, so the campaigns can see the whole journey and not only the final sale:
- page_viewed: a visitor lands on a page
- contents_viewed: a visitor views a product
- items_added: a product is added to the basket
- checkout_started: the visitor begins checkout
- order_created: the purchase completes
Custom conversion events aren’t supported for that optimisation objective at the moment.
Create the Conversions API key
This turned out to be one of the most tricky parts of the implementation.
You need an API key for the server-side Conversions API request.
In Ads Manager go to Tools then Conversions, open Manage conversion keys and choose Create new key.
Give it a recognisable name such as GTM CAPI API. Copy the key when it’s generated and store it securely.
The key belongs in your server GTM container. Don’t expose it in web GTM or in website code. The Pixel ID isn’t a secret in the same way; the Conversions API key is.
For this implementation, creating the key through Manage conversion keys proved to be the reliable route. There’s a longer explanation of why in the troubleshooting section below.
Step 2: Set up the OpenAI Pixel in web GTM
Install the Stape web GTM template
Open your web GTM container and go to Templates the Search Gallery.
Search for OpenAI Ads Pixel by Stape, accept and add the template.
Create a new tag using this template. We called ours OpenAI Conversion Tag.
Configure the web OpenAI Pixel
Enter the OpenAI Pixel ID from your Data Source. I prefer putting the ID into a GTM Constant variable rather than typing it into every tag.
For our lead event, configure:
- Event Name Setup Method: Override
- Event Type: Standard
- Event Name:
lead_created
Why Override?
Our website event is called generate_lead, but the OpenAI standard event we want to send is lead_created. So we’re explicitly mapping one to the other.
Stape also supports inheriting and mapping event names, which is useful for larger ecommerce implementations where you have several events to map.
Configure user data
Under User Identifiers Parameters, add:
Email Address → {{DLV - user_data.email_address}}
Our website already provides the email address inside user_data.email_address, so we’re reading that value with a Data Layer Variable.
Keep Enable Advanced Matching → ON.
Don’t add an email address as an ordinary GA4 custom event parameter just to make this work. Handle user data through the user-data functionality built for it.
Add the conversion value
Under Event Parameters, we added:
- Amount (in the currency’s regular unit) →
{{DLV - lead_value}} - Currency →
{{DLV - lead_currency}}
Our example therefore sends:
Amount: 1136
Currency: GBPThe Stape server template converts the amount into the format the OpenAI API requires. In our successful outgoing request, £1,136 appeared as:
amount: 113600
currency: GBPThat’s expected. The API request represents the amount in the currency’s lowest unit, so pence rather than pounds.
Create the Event ID
This is the part that matters if you’re using both the browser Pixel and the server-side Conversions API.
Install Stape’s Unique Event ID variable template and create a variable from it. We called ours OpenAI Event ID.
In the OpenAI web tag, go to Server Side Tracking Settings → Event ID and select {{OpenAI Event ID}}.
The actual ID doesn’t matter. What matters is that the same ID reaches both OpenAI requests.
Pass the Event ID to server GTM
This was the missing step in our first implementation.
Generating the Event ID for the OpenAI web Pixel isn’t enough. Server GTM also needs to receive it.
We’re already sending our generate_lead event from web GTM to server GTM through GA4. So open the existing GA4 Event – generate_lead tag and add this Event Parameter:
event_idwith the value:
{{OpenAI Event ID}}The flow is now:
generate_lead
↓
OpenAI Event ID
↓
┌───────────────┬────────────────┐
↓ ↓
OpenAI Pixel GA4 generate_lead
↓ ↓
lead_created event_id
↓
Server GTMIn our final test, the GA4 event and the OpenAI web Pixel both contained exactly the same Event ID.
Configure consent
In the web OpenAI tag, set Enable Google Consent Mode support → ON.
We also use the appropriate ad_storage consent state.
Your consent implementation depends on your CMP and your legal requirements, so don’t copy another website’s consent configuration.
Step 3: Set up the OpenAI Conversions API in server GTM
Add the server GTM template
Move into your server GTM container and add the Stape template OpenAI Ads Conversions API by Stape.
Create a tag called something like OpenAI CAPI Tag.
Configure the server OpenAI tag
For our lead implementation we used:
- Event Name Setup Method: Standard
- Event Name:
lead_created - Pixel ID: the same Pixel ID used by the web tag
- API Key: your Conversions API key
- Action Source: Web
- Validate Only: False
- Use Optimistic Scenario: False while testing
Leaving Optimistic Scenario off during implementation means you can see whether OpenAI actually accepted the request, rather than the tag reporting success before the API has responded.
Configure the server Event ID
Create a server GTM Event Data variable with its Key Path set to:
event_idWe called ours Event Data – Event ID.
In the OpenAI CAPI tag, under Server Event Data Parameters, set:
Event ID → {{Event Data - Event ID}}
Keep Automap Server Event Data Parameters → ON.
For this hybrid Pixel and CAPI implementation we set Autogenerate an Event ID if none is found → OFF.
That’s deliberate. If the Event ID doesn’t arrive from web GTM, I would rather see the server tag fail during testing than have it create a different ID and lose the ability to deduplicate the browser and server events.
Configure server-side user data
Keep Automap User Data Parameters → ON.
Our incoming server GTM event contained user_data.email_address. The successful OpenAI request contained a SHA-256 hashed email rather than the plain address, which gives OpenAI another signal for matching the website conversion back to an eligible ad interaction.
Configure the server conversion value
Under Event Parameters add:
- Amount (regular unit) → Server Event Data
value - Currency → Server Event Data
currency
Our incoming event contained:
value: 1136
currency: GBPand the successful outgoing OpenAI request contained:
currency: GBP
amount: 113600So don’t convert £1,136 to 113600 yourself when you’re using Stape’s regular unit field. The template handles that.
Configure the OpenAI click reference
The Stape server template supports OpenAI’s click reference and can manage the oppref value server-side.
For testing we used a dummy oppref in the landing-page URL, which let us confirm the value made it all the way into the server request.
A dummy value only proves the implementation works. It doesn’t create genuine OpenAI attribution. For that you need an eligible interaction with a real ChatGPT ad.
Set the server GTM trigger
Fire the CAPI tag on the server-side event that represents the genuine conversion. For us that’s generate_lead, which the server tag then maps to lead_created for OpenAI.
Don’t fire the CAPI tag on every GA4 request. It should only fire for the event you’re sending to OpenAI.
Step 4: Test the whole flow
Test the web Pixel
Start web GTM Preview and complete the contact form.
Open the generate_lead event and check the OpenAI tag. We verified:
Firing Status: Succeeded
Event Name: lead_created
Event Type: standard
Email: populated
Amount: 1136
Currency: GBP
Event ID: populatedCopy or note the Event ID, because you’re going to compare it with the server event.
Test server GTM
Open server GTM Preview at the same time and complete another test conversion.
Find the incoming generate_lead and inspect Event Data first. You should see:
event_name: generate_lead
event_id: [your event ID]
value: 1136
currency: GBP
user_data: ...If event_id is missing here, don’t start changing the OpenAI CAPI tag. The problem is upstream. Check that your web GTM GA4 event is sending:
event_id → {{OpenAI Event ID}}That was one of the main problems we found during this implementation.
Check deduplication
Compare the Event ID in the OpenAI web Pixel with the Event ID sent by the OpenAI CAPI tag. They must be identical for the same conversion.
Our final test produced the same ID all the way through:
OpenAI Web Pixel
↓
GA4 generate_lead
↓
Server GTM
↓
OpenAI CAPIThis is what allows OpenAI to recognise the browser and server events as the same conversion rather than counting two separate leads.
Check the outgoing OpenAI CAPI request
In server GTM Preview, open the outgoing request to OpenAI. Our successful request contained:
type: lead_created
action_source: web
event_id: [matching Event ID]
user:
email_sha256
ip_address
user_agent
obref
data:
type: customer_action
currency: GBP
amount: 113600Most importantly, the response was:
Status Code: 200That proves OpenAI accepted the server-side event.
Check Ads Manager
Return to Ads Manager → Tools → Conversions and check the Data Source and Event Stream.
There’s an important distinction here. Event received means the implementation is sending data successfully. Attributed conversion means OpenAI has also connected that event with an eligible advertising interaction and the campaign’s configured conversion event.
Don’t assume an accepted test event will immediately appear as an attributed campaign conversion.
Troubleshooting: the Conversions API key problem we hit
This deserves its own section because the implementation looked correct but initially failed.
Our first outgoing request reached OpenAI but returned:
HTTP 401with an error saying the key was missing the scope:
ads.third_party_events.writeAt that point the payload was already correct. Event ID, hashed email, value and the other parameters were all reaching the OpenAI endpoint. The problem was the API key.
What fixed it
We went back to Ads Manager → Tools → Conversions, opened Manage conversion keys and created a new Conversion key there.
We replaced the previous key in server GTM without changing anything else. The next request returned:
HTTP 200What I'd recommend
Create the CAPI credential through Tools → Conversions → Manage conversion keys → Create new key. That route makes it clear you’re creating a key specifically for conversion measurement.
OpenAI’s current documentation requires a Pixel ID and a Conversions API key for conversion measurement integrations. There are other API-key areas within the wider OpenAI interface, so I wouldn’t claim another route can never work. What we can say from our test is that for our direct Stape server GTM implementation, creating a fresh key from Manage conversion keys resolved the 401 missing-scope error immediately.
So if you get:
401
Missing scopes: ads.third_party_events.writeand the rest of the request looks correct, create a fresh key through Manage conversion keys before you start changing the GTM implementation. It could save you a lot of unnecessary debugging.
Step 5: Link the conversion to your campaign
Ads Manager’s setup checklist includes Link event to a campaign.
You don’t need to create a campaign to prove the Pixel and CAPI implementation works. But you do need to associate the conversion with your advertising if you want OpenAI to use it for campaign conversion measurement and optimisation.
For a conversion-optimised campaign, create a campaign with Objective → Conversions and select the standard conversion event you want the campaign to optimise towards. For our example that’s Lead Created.
Decide which conversion you want to optimise towards before launching the campaign.
Final checks before you publish GTM
I’d want all of these to pass before publishing either container:
- Web Pixel fires
-
lead_createdsent - Email available for Advanced Matching
- Value and currency correct
- Event ID generated
- GA4 transports the Event ID to sGTM
- Server receives the same Event ID
- CAPI sends the hashed email
-
opprefcan be captured - Web and CAPI Event IDs match
- OpenAI CAPI response is HTTP 200
- Event visible in Ads Manager
That’s the configuration we successfully tested end to end. The same checks, plus every setting that feeds them, are in the PDF checklist at the bottom of this post.
Frequently asked questions
You can run the Pixel alone, but you’ll lose conversions to ad blockers, browser tracking protection and consent choices. The Conversions API sends the conversion from your server, so it isn’t affected by those. Running both, with a shared Event ID, gives OpenAI the most complete picture without double counting.
The OpenAI API represents amounts in the currency’s lowest unit, so pounds become pence. Stape’s template does the conversion for you when you use the “regular unit” amount field. Enter 1136, not 113600.
In Ads Manager go to Tools, then Conversions, then Manage conversion keys, and create a new key. In our testing, a key created elsewhere in the OpenAI interface returned a 401 “missing scopes: ads.third_party_events.write” error, and a fresh key from Manage conversion keys fixed it.
Almost always the web side. Check that your GA4 event tag in web GTM is sending an event_id parameter with the same Unique Event ID variable you gave the OpenAI Pixel tag. If that parameter isn’t there, server GTM has nothing to read.
Not for conversion-optimised campaigns at the moment. OpenAI requires a supported standard event such as lead_created, order_created, subscription_created or registration_completed for that objective.
Download the checklist
Every setting in this guide, in the order you need to make it, on six pages you can print or keep open in a second window. Each step has a tick box and a space to write the value you used (Pixel ID, variable names, trigger, sign-off date), so the person who audits the setup later can see exactly what was configured. It includes the troubleshooting table for the 401 missing-scope error and the missing Event ID.
No email address required.
Need this set up on your site?
I set this up on our own site first so I could see where it breaks. If you’d rather not spend an afternoon in two GTM containers and the OpenAI API, book a free tracking audit and I’ll tell you what your ChatGPT Ads tracking is doing today and what it would take to make it hold up.

Neal Cole
Neal Cole is the founder of Conversion Uplift, a UK digital analytics consultancy, and wrote the official GA4 and GTM audit course for CXL. He works with marketing teams who spend real money on acquisition and want numbers they can stand behind.










