If you already run server-side Google Tag Manager for GA4, Google Ads or Meta, adding ChatGPT Ads to it is a natural next step. The OpenAI Conversions API is built to receive events from a server, and a server container is exactly that: a server you control that receives your website's events and forwards them to each ad platform.
In this guide I explain how I would send ChatGPT Ads conversions with server-side GTM on Stape or Google Cloud: build options, click reference, hashing, deduplication and consent. The platform is still evolving, so confirm details in OpenAI's docs.
Why send ChatGPT Ads conversions server-side?
Sending ChatGPT Ads conversions server-side makes them more reliable, because the event no longer depends on a script loading in the visitor's browser. Ad blockers, browser tracking protection, slow thank-you pages and closed tabs all lose browser events. A server event fired after your backend confirms the order does not suffer from any of those.
OpenAI's own developer docs call the Conversions API (CAPI) the more reliable source for conversion-optimised campaigns. There is a second benefit: your API key stays on the server. OpenAI's pixel docs specifically warn against calling the Conversions API from page code, because the key would be visible to anyone.
If server-side tagging is new to you, read what server-side tracking is and whether you need it first.
What does the server-side flow look like?
The server-side flow takes an event from your website, enriches it in the server container and forwards it to OpenAI.
- The visitor clicks a ChatGPT ad and lands on your site with an
opprefparameter in the URL. - The OpenAI pixel in your web container stores
opprefin a first-party cookie (__oppref) and fires browser events. - Your web container also sends the same event (for example, through a GA4 tag) to your server container on a first-party subdomain such as
sst.example.com. - A tag in the server container builds a Conversions API request: event type, event ID,
oppref, value, currency and hashed user data. - OpenAI receives both the browser and server events, keeps the first and ignores the duplicate.
Which build options do you have?
You have three practical ways to send ChatGPT Ads conversions server-side, and the right one depends on where your conversion data lives.
| Option | How it works | Good for | Watch out for |
|---|---|---|---|
| A. sGTM community template | A ready-made OpenAI Conversions API tag in the server container | Most sites already on sGTM | Not built by OpenAI or Google; check updates |
| B. Custom HTTP request | Your own sGTM template that sends the request to the CAPI endpoint | Unusual data needs, full control | You maintain the payload when the API changes |
| C. Backend or CRM webhook | Your server, CRM or automation tool calls CAPI directly | Offline sales, booked jobs, subscriptions | Needs the click reference stored with the lead |
Option A: use a community sGTM template
At the time of writing, I am not aware of an official OpenAI tag for server-side GTM. Stape has published an open-source OpenAI (ChatGPT) Conversions API tag for server containers, with a companion web pixel tag, and TAGGRS publishes another sGTM template. These are available through GitHub and the GTM Template Gallery.
A typical setup:
- In your server container, add the OpenAI Conversions API template from the Template Gallery.
- Enter your Pixel ID and API key (from the Conversions tab in ChatGPT Ads Manager).
- Map the incoming event name to OpenAI's event type, for example
purchasetoorder_createdandgenerate_leadtolead_created. - Map the event ID, value, currency and user data from the event data.
- Trigger the tag only on your conversion events, not on every page view.
One detail reported in Stape's documentation: OpenAI represents amounts in the currency's smallest unit (cents rather than dollars), and the template can convert for you. Check how your chosen template handles value, and compare one test order in Ads Manager against your shop.
Option B: build your own HTTP request
If a template does not fit, write a custom sGTM template that uses the sandboxed sendHttpRequest API to post to the Conversions API endpoint. Take the endpoint, authentication and field names from OpenAI's Conversions API reference. You then own every future API change, so I only do this when templates fall short.
Option C: send from your backend or CRM
For businesses whose real conversion happens later, such as a booked cleaning job or a closed deal, the best source is the system that records it. Store the oppref value and the customer's contact details with the lead when the form is submitted, then send the conversion from your backend, CRM or an automation tool (Zapier, Make, a GoHighLevel webhook) when the status changes. The same idea powers offline conversion tracking for Google Ads.
How do you pass the oppref click reference?
You pass the click reference by reading it in the browser and sending it to your server container as an event parameter. Unlike the pixel, the Conversions API does not pick up oppref on its own.
In the web container, create a first-party cookie variable for __oppref (with a URL query variable for oppref as a fallback) and add it as a parameter on your GA4 event, for example oppref. In the server container, map that parameter into the template's click reference field. For CRM flows, save the same value in a hidden form field. OpenAI's troubleshooting docs recommend preserving the real click reference through the visit and including it in server events whenever it is available.
How should you hash user data?
User data must be normalised and hashed with SHA-256 before it is sent, and raw personal data should never leave your systems. For email, OpenAI's docs describe trimming whitespace, lowercasing and sending the 64-character lowercase hex digest in the emails_sha256 field.
// normalise before hashing
const email = ' Jane.Doe@Example.com '.trim().toLowerCase();
// -> 'jane.doe@example.com', then SHA-256 -> 64-char lowercase hex
Hash in the web container, the server container (sGTM has a sha256 API) or your backend, but only once. Check the Conversions API reference for the other identifiers it accepts and their exact normalisation rules.
How does deduplication work with the browser pixel?
Deduplication works by giving the pixel event and the server event the same ID. OpenAI matches events on Pixel ID, event name and event ID; the first one received is kept and later copies are ignored. In the Conversions API, the ID goes in the event's id field and should equal the pixel's event_id.
The easiest method is to generate the ID once, in the dataLayer push (an order number works well for purchases), and read it in both the web pixel tag and the GA4 event that feeds the server container. Retries of the same event must reuse the ID; a new conversion needs a new one. This is the same pattern I explain for Meta in Meta CAPI event deduplication.
Where does consent fit server-side?
Consent still applies when events go server-side; moving tracking to a server does not remove your obligations. OpenAI's docs say to follow your site's consent requirements before collecting or forwarding the click reference, and to stop sending it if a user withdraws consent.
In practice:
- Pass the user's consent state from the web container to the server container with each event.
- Add a condition to the OpenAI tag so it does not fire, or sends no user data and no click reference, when advertising consent is denied.
- Keep the browser pixel's own consent setting in sync with your banner.
If you use Consent Mode v2, the ad_storage and ad_user_data signals are a sensible basis for these rules, but get legal advice on what your market requires.
How do you test the server-side setup?
Test the setup in sGTM Preview first, then with OpenAI's validation tools.
- In sGTM Preview, confirm the OpenAI tag fires once per conversion and the outgoing request returns a success status.
- Check the request includes the event ID,
oppref(when present) and hashed, not raw, user data. - Use the Conversions API's
validate_onlyoption while building, which checks events without saving them. - Place a real test order after an ad click and confirm a single conversion in Ads Manager after 24 to 48 hours.
Final thoughts
Server-side GTM is the cleanest way to send ChatGPT Ads conversions if you already run a server container, and a backend or CRM webhook is best when the sale happens later. Whichever route you pick, get the event ID, click reference and consent right. My ChatGPT Ads tracking service covers this build on Stape or Google Cloud, or you can book a free tracking audit.


