OpenAI Ads Conversions API
Datafly Signal delivers conversion events to OpenAI Ads (ChatGPT Ads) server-to-server using the Conversions API. This feeds OpenAI’s conversion-optimised campaign objective and provides reliable measurement that is not affected by ad blockers or browser tracking prevention.
Prerequisites
Before configuring OpenAI Ads in Signal, you need an OpenAI Ads account with an active Pixel and a Conversions API key.
Step 1: Create an OpenAI Ads account
If you don’t already have one, sign up at ads.openai.com and complete the advertiser onboarding for the ChatGPT Ads Manager.
Step 2: Create or find your Pixel
- In ChatGPT Ads Manager, open the Conversions tab.
- If you already have a Pixel, note its Pixel ID (used as the
pidparameter). - To create a new Pixel, follow the Set up conversions flow and note the Pixel ID it generates.
Use the same Pixel ID for your JavaScript pixel and the Conversions API so that events sent from both sides can be deduplicated.
Step 3: Generate a Conversions API key
- Still in the Conversions tab, generate a Conversions API key.
- Copy the key immediately and store it securely — it grants write access to your pixel’s conversions.
Configure in Signal
Configuration fields
| Field | Required | Description |
|---|---|---|
pixel_id | Yes | Your OpenAI Ads Pixel ID. Sent as the pid query parameter. |
api_key | Yes | Conversions API key, sent as Authorization: Bearer <key>. |
validate_only | No | When true, events are validated but not recorded. Use during setup, then remove for production. |
Management UI setup
Add the integration
Go to Integrations > Add Integration > OpenAI Ads.
Enter credentials
Enter your pixel_id and api_key.
Select consent categories
Select the consent category that governs advertising (typically marketing or advertising). Signal uses this to set opt_out per event.
Save
Click Save. To verify before going live, enable Validate Only first.
API Endpoint
POST https://bzr.openai.com/v1/events?pid={pixel_id}
Authorization: Bearer {api_key}
Content-Type: application/jsonEvents are sent as a JSON array under the events key. OpenAI accepts up to 1,000 events per request. timestamp_ms must be within the last 7 days and no more than 10 minutes in the future.
Identity Signals
OpenAI matches server events to ad exposure using the signals below. The more you provide, the better the match rate and conversion optimisation.
Automatic signals
These are sent automatically by Signal — no configuration needed:
| Signal | Field | Description |
|---|---|---|
external_id | user.external_id | Set to the Datafly anonymous_id. A stable first-party identifier. |
ip_address | user.ip_address | Visitor’s IP address, forwarded from the original request. |
user_agent | user.user_agent | Visitor’s User-Agent string, forwarded from the original request. |
oppref | oppref | OpenAI’s privacy-preserving click identifier, captured from the landing URL when present. |
User-provided signals (hashed)
When a user is identified via datafly.identify() with traits, these fields are SHA-256 hashed before sending to OpenAI:
| Signal | Hashing | Description |
|---|---|---|
email (user.email) | SHA-256, lowercase, trimmed | User’s email address |
phone_number (user.phone_number) | SHA-256, E.164 normalised | User’s phone number |
All PII hashing is performed server-side by Signal before the data leaves your infrastructure. Raw email and phone are never sent to OpenAI.
How to send user data
Call datafly.identify() when a user logs in, registers, or submits a form:
datafly.identify("user-123", {
email: "jane.doe@example.com",
phone: "+44 7700 900123"
});Signal normalises and hashes these fields automatically before delivery.
Event Mapping
Default preset
| Signal event | OpenAI event type | Data shape |
|---|---|---|
page | page_viewed | contents |
Product Viewed | contents_viewed | contents |
Product Added | items_added | contents |
Checkout Started | checkout_started | contents |
Order Completed | order_created | contents |
Lead Generated | lead_created | customer_action |
Signed Up | registration_completed | customer_action |
Trial Started | trial_started | plan_enrollment |
Subscription Started | subscription_created | plan_enrollment |
To customise, edit the integration’s Field Mappings in the Management UI.
Example: Purchase event
Datafly.js call:
datafly.track("Order Completed", {
order_id: "ORD-001",
revenue: 129.99,
currency: "USD",
products: [
{ product_id: "SKU-A", product_name: "Widget", quantity: 2 },
{ product_id: "SKU-B", product_name: "Gadget", quantity: 1 }
]
});OpenAI Ads payload sent by Signal:
{
"events": [
{
"id": "evt_abc123def456",
"type": "order_created",
"timestamp_ms": 1717660800000,
"action_source": "web",
"source_url": "https://example.com/checkout/confirmation",
"opt_out": false,
"user": {
"email": "a1b2c3...",
"external_id": "anon_98f2...",
"ip_address": "203.0.113.50",
"user_agent": "Mozilla/5.0 ..."
},
"data": {
"type": "contents",
"amount": 129.99,
"currency": "USD",
"order_id": "ORD-001",
"contents": [
{ "id": "SKU-A", "name": "Widget", "quantity": 2 },
{ "id": "SKU-B", "name": "Gadget", "quantity": 1 }
]
}
}
]
}OpenAI expects data.amount in the lowest denomination of the currency (for example, cents for USD). Confirm whether your revenue values need to be converted to minor units and add a multiply transform in Field Mappings if so.
Consent
Signal maps your canonical marketing consent state to the per-event opt_out flag. When marketing consent is granted, opt_out is false; when it is denied or absent, opt_out is true, which excludes the event from user-level personalisation.
Testing your integration
Enable Validate Only
Set validate_only to true in the integration config. Events are validated by OpenAI but not recorded for optimisation or reporting.
Trigger events
Trigger conversions on your website and confirm Signal receives a success response in the event debugger.
Verify in Ads Manager
Disable Validate Only, trigger a real conversion, and confirm it appears in the Conversions tab in ChatGPT Ads Manager.
Remember to turn off Validate Only before going to production, otherwise no conversions will be recorded.
Deduplication
If you run both Signal server-side delivery and the OpenAI JavaScript pixel during a migration period, deduplicate to prevent double-counting:
- Use the same value for the Conversions API
idand the pixelevent_id. - Send both with the same Pixel ID.
- For custom events, use the same
custom_event_nameon both sides.
Signal includes a unique id with every event. OpenAI deduplicates events that share the same id and type.
Troubleshooting
| Problem | Solution |
|---|---|
| Events not appearing | Confirm pixel_id matches your Pixel and api_key is valid. Disable validate_only. |
401 Unauthorized | The API key is invalid or expired. Generate a new one in the Conversions tab. |
403 Forbidden | The API key is not authorised for this Pixel ID. |
| Timestamp rejected | timestamp_ms must be within the last 7 days and under 10 minutes in the future. |
| Whole batch rejected | A single malformed event fails the entire batch. Inspect the payload in Signal’s event debugger. |
| Low match rate | Send email and phone via datafly.identify(); ensure external_id, IP and User-Agent are present. |