OpenAI Ads Standard Events vs Custom Events
Use a standard event whenever one fits the action you're tracking. Use a custom event — with a
custom_event_nameyou define — only for actions the standard set doesn't cover, likequote_requested,appointment_scheduled, orconfigurator_completed. Both are fully supported by the OpenAI Ads pixel and Conversions API; the choice is simply about matching your action to the right taxonomy.
This sounds like a small decision, but it shapes your whole implementation: get it wrong and you end up either forcing an action into a standard event it doesn't really describe, or inventing a custom event for something that already has a perfectly good standard name. Below is the full standard event list, how custom events actually work in code, worked examples, and a checklist for deciding which to use.
The standard event list
OpenAI Ads defines a fixed set of standard events, each tied to a specific data shape:
| Event | Data shape | Fires when |
|---|---|---|
page_viewed | contents | A visitor lands on or views an important page — fires automatically once the pixel loads |
contents_viewed | contents | A visitor views a specific product, listing, article, or content unit |
items_added | contents | A visitor adds one or more items to a cart, bundle, or selection |
checkout_started | contents | A visitor starts the checkout process |
order_created | contents | A purchase completes |
lead_created | customer_action | A visitor submits a lead form or requests contact |
registration_completed | customer_action | A visitor finishes an account or event registration flow |
subscription_created | plan_enrollment | A paid subscription starts |
trial_started | plan_enrollment | A free trial starts |
app_installed | customer_action | A user installs an app — Conversions API only, not supported by the pixel |
app_opened | customer_action | A user opens an app — Conversions API only, not supported by the pixel |
app_installed and app_opened need action_source set to mobile_app and can only be sent server-side; there's no pixel path for mobile app lifecycle events. Every other standard event works from both the pixel (oaiq("measure", ...)) and the Conversions API.
Notice what isn't on this list: appointment bookings, quote requests, configurator completions, demo signups that don't go through a "registration" flow, content downloads, and dozens of other actions businesses commonly want to track. None of those are standard events. That's exactly what custom events are for.
What a custom event is and how it works
A custom event is any action you define yourself, using type: "custom" and a required custom_event_name field that becomes the event's identity. Per the supported events reference, the custom data shape sits alongside the other three shapes (contents, customer_action, plan_enrollment) — it's a first-class event type, not a fallback or a hack.
On the pixel, options carries the custom_event_name:
oaiq("measure", "quote_requested", {
type: "custom"
}, {
custom_event_name: "quote_requested"
});
On the Conversions API, per the Conversions API reference, the event object needs type: "custom" and custom_event_name alongside the standard required fields (id, timestamp_ms, data):
{
"id": "quote_9f21a",
"type": "custom",
"custom_event_name": "quote_requested",
"timestamp_ms": 1756310400000,
"action_source": "web",
"source_url": "https://example.com/quote/confirmation",
"data": {
"type": "custom"
}
}
The custom data shape can also carry amount, currency, contents, or plan_id if the action has monetary value or associated items — same field rules as the standard shapes: any amount requires a currency, and amounts are ISO 4217 minor-unit integers.
Worked examples of good custom events
A few actions that don't map to any standard event, and how you'd implement them:
quote_requested — a visitor submits a request for a custom quote (common for B2B, services, or made-to-order products where price isn't fixed). This isn't lead_created, because a quote request is a specific, higher-intent action you likely want to measure separately from a general contact form.
oaiq("measure", "quote_requested", { type: "custom" }, { custom_event_name: "quote_requested" });
appointment_scheduled — a visitor books a meeting, demo, or consultation. This is not a standard event in OpenAI Ads' taxonomy, so it's implemented as a custom event rather than forced into registration_completed or lead_created, which describe different actions.
oaiq("measure", "appointment_scheduled", { type: "custom" }, { custom_event_name: "appointment_scheduled" });
configurator_completed — a visitor finishes configuring a product (common for furniture, vehicles, or anything with a "build yours" flow) before moving to purchase. This is a meaningful mid-funnel signal that doesn't fit items_added (nothing's been added to a cart yet) or contents_viewed (it's an interaction, not a view).
oaiq("measure", "configurator_completed", { type: "custom" }, { custom_event_name: "configurator_completed" });
In each case, the pattern is the same: the action is real, it's worth measuring, and none of the nine standard events accurately describes it. That's the test — not whether an event "sounds important," but whether it's actually a different action than what the standard taxonomy already covers.
Why standard-first matters
It's tempting to reach for custom events by default, since you control the naming and the shape. Resist that. Two reasons standard events should be your first choice whenever one genuinely fits:
The platform already understands them. Standard events map to a recognized taxonomy that OpenAI Ads' optimization and reporting are built around. A custom event still gets counted and reported, but it's an arbitrary name you defined — there's no shared definition the platform has already built expectations around the way it has for order_created or lead_created.
Custom events only work if the naming is consistent. A standard event name is fixed — you can't misspell order_created into meaninglessness because there's only one correct spelling to use. A custom event has no such guardrail. If one part of your team fires quote_requested and another fires quote_submitted for the same action, you now have two disconnected events instead of one coherent one. Standard events remove this entire failure mode; custom events require you to police it yourself.
None of this means custom events are a lesser option — they're the correct choice for anything outside the standard taxonomy, and OpenAI Ads treats them as real, measurable events. It just means "does a standard event fit?" should always be the first question, not an afterthought.
Deduplication nuance for custom events
If you're sending the same conversion from both the pixel and the Conversions API — the recommended setup for reliability — deduplication for a standard event matches on Pixel ID plus the event identifier (event_id on the pixel, id on the Conversions API).
For a custom event, there's one more requirement: custom_event_name has to match exactly between the two calls, in addition to the Pixel ID and event ID. If your pixel call uses custom_event_name: "quote_requested" and your server-side call uses custom_event_name: "quote_request" (dropped the "ed") for what's meant to be the same action, OpenAI Ads won't recognize them as duplicates — you'll get two separate events instead of one deduplicated event, quietly inflating your count for that action. See deduplicating pixel and Conversions API event IDs for the full mechanics of how this matching works.
Naming conventions and a decision checklist
A few conventions worth adopting before you name your first custom event:
- Use
snake_case, matching the standard events (quote_requested, notQuoteRequestedorquote-requested). Consistency with the existing taxonomy makes your event list easier to scan later. - Name the action, not the page.
appointment_scheduleddescribes what happened;booking_page_thank_youdescribes where it happened. The former is reusable if that action ever happens from a different page; the latter breaks the moment your page structure changes. - Write the exact string down somewhere your whole team can see it — a shared doc, a tracking plan, a code comment near the implementation. The failure mode above (mismatched names breaking dedup, or two people inventing two names for one action) is almost always a documentation gap, not a technical one.
- Reuse an existing custom event name before creating a new one. If you already track
quote_requestedand a new page introduces a similar "request a callback" action, decide deliberately whether that's the same event or a genuinely different one — don't let near-duplicate custom events accumulate by accident.
Decision checklist, in order:
- Does one of the nine standard events (
page_viewed,contents_viewed,items_added,checkout_started,order_created,lead_created,registration_completed,subscription_created,trial_started) accurately describe this action? If yes, use it — don't create a custom event for something a standard event already covers. - Is this an app install or app open? Those are
app_installed/app_opened, sent via the Conversions API only, withaction_source: "mobile_app". - If neither applies, this is a custom event. Give it a clear, action-based
snake_casename, document it, and use that exactcustom_event_nameeverywhere you fire it — pixel and Conversions API alike. - If you're sending it from both the pixel and server-side, confirm the
custom_event_namematches exactly on both calls before you consider the implementation done.
Where to go from here
Getting this mapping right once, at the start, is a lot cheaper than untangling mismatched or misused events later. If you want your funnel mapped to the correct standard and custom events and implemented cleanly from the start, Pixel Setup covers exactly that. If you also want the Conversions API implemented alongside it — with deduplication configured correctly across both — the full Pixel + CAPI Setup does both in one build.
Want this done for you?
Fixed-scope setup, tested end-to-end and documented.
Explore the serviceTake the free audit