Guide

How to Preserve OpenAI Ads Attribution with UTM Parameters

OpenAI Ads attribution rides on a single value carried in the landing URL, called oppref. The pixel reads that value on first page load and stores it in a first-party __oppref cookie for roughly 30 days, then attaches it automatically to every pixel event that follows. If anything strips that parameter from the URL before the pixel loads — a redirect, a consent wall, an http→https hop, a URL shortener — attribution breaks even when your pixel and Conversions API events are firing perfectly. The events are real; they're just no longer tied to the ad that produced them.

This is one of the more frustrating tracking failures to diagnose, because nothing looks broken from the usual vantage points. Ads Manager shows conversions. Your backend shows matching orders. Debug mode confirms events are received. And the campaign still looks like it's underperforming, because a meaningful share of conversions that actually came from your ChatGPT ads are landing as unattributed or misattributed traffic instead.

How attribution actually flows

Understanding the chain end to end is what makes each failure point obvious once you know where to look:

  1. A user clicks your ad in ChatGPT. OpenAI appends an oppref value to the destination URL you configured for that ad.
  2. The browser lands on your page with that value present as a URL parameter.
  3. The pixel's oaiq("init", ...) call reads the parameter on that page load and writes it into a first-party __oppref cookie, good for roughly a 30-day attribution window.
  4. Every subsequent oaiq("measure", ...) call — page views, cart adds, the eventual purchase — automatically includes that cookie value, so OpenAI's system can tie the later conversion back to the original ad click, even if the conversion happens on a different page or a different day within the window.
  5. If you're also running the Conversions API, step 4 does not happen automatically. CAPI has no browser context and no access to cookies — your server has to read the __oppref value (typically from the request, a session, or stored order metadata) and include it explicitly in the event payload it sends.

The critical point: everything from step 2 onward depends on the parameter surviving intact to the moment the pixel first loads. Lose it before that, and there's no value for the cookie to store — steps 3 through 5 have nothing to work with, regardless of how correctly the rest of your tracking is built.

The parameter-killers, and the fix for each

These are the specific mechanisms that strip oppref (and, not coincidentally, often your UTM parameters too) before the pixel gets a chance to read them.

Redirect chains that drop query strings. A common pattern: your ad's destination URL points to /landing, which 301-redirects to /landing/ (trailing slash normalization) or to a campaign-specific variant, and the redirect logic constructs the new URL without forwarding the original query string. The fix is to audit every redirect rule your landing pages pass through — server config, CDN rules, page-builder redirect settings — and confirm each one explicitly appends req.query (or your platform's equivalent) to the destination rather than hardcoding a bare path.

Consent walls and interstitials that navigate. If a cookie-consent gate or an age/region interstitial sends the visitor to a new page after they interact with it, rather than just revealing content on the same page, that navigation is a fresh page load — and if the interstitial's own URL doesn't carry the original query string forward, oppref is gone before the real landing page ever renders. Fix: make consent gates overlay the existing page instead of redirecting, or if a redirect is unavoidable, forward the query string through it.

Misconfigured http→https or www-canonicalizing redirects. Many sites force http:// to https://, or example.com to www.example.com (or the reverse), via a redirect rule. These are usually implemented correctly, but it's worth confirming directly rather than assuming — a bare location: https://example.com/ in a redirect handler, written without forwarding the original path and query, silently drops every parameter on every single visit that happens to hit the non-canonical form first.

URL shorteners. If you shorten your ad destination URL for any reason (rare for paid ad destinations, but it happens when a URL is copied into a channel with length limits, or reused from another channel's process), confirm the shortener preserves query parameters through the redirect rather than pointing to a bare destination URL with the parameters baked in only at creation time and lost on click.

In-app browsers. Traffic opened inside an in-app browser (common depending on where a link is shared or opened) can behave differently around query strings and first-party cookie storage than a standard browser tab, depending on the app's webview implementation. This isn't something you can fully control, but it's worth knowing as a source of attribution gaps that isn't a bug in your own setup.

"Clean URL" plugins and tools. Some SEO or performance plugins, browser extensions, and even certain analytics tools actively strip tracking parameters from URLs, sometimes as a stated privacy feature, sometimes as an unintended side effect of a "canonical URL" or "remove tracking params" setting. If you've enabled anything on your own site that describes itself as cleaning, canonicalizing, or de-cluttering URLs, check whether oppref and your UTMs are on its exclusion list — most tools that do this have one, but it's opt-in, not automatic.

UTMs and oppref: run both, don't confuse them

UTM parameters (utm_source, utm_medium, utm_campaign, and related) are for your own analytics — GA4 or whatever platform you use to understand traffic sources across all channels, not just ChatGPT ads. oppref is a separate, OpenAI-specific value that exists purely to drive attribution inside OpenAI Ads Manager. They serve different systems, and one does not substitute for the other.

This matters in practice because it's easy to assume "we already have UTM tracking, so attribution is covered" — and that assumption is wrong specifically for OpenAI Ads reporting. Your GA4 reports can show a channel correctly while Ads Manager shows the same conversion as unattributed, if oppref was lost along the way while your UTMs happened to survive (or vice versa — the two parameters can be stripped independently of each other depending on exactly how a redirect or rewrite rule is written).

The practical rule: whatever you do to your landing page URLs — redirect logic, canonicalization, consent handling, a "clean URL" feature — has to preserve both parameter sets, not just the one your team happens to be checking. Auditing one and assuming the other survived is a common way this gap goes unnoticed for months.

Persisting oppref server-side for CAPI

If you're sending conversion events through the Conversions API — which OpenAI's own measurement guidance recommends running alongside the pixel — remember that CAPI does not automatically pick up the __oppref cookie. Your backend has to capture it and carry it through to the eventual conversion event, which is usually a multi-step job since orders and cookie reads rarely happen in the same request.

A practical pattern:

  1. On the landing page request, read the __oppref cookie value (set by the pixel on a prior page load, or read directly from the URL parameter if this is the same request that set it).
  2. Store it against the session or user record — most backends already have a session object or a cart/order draft this can attach to.
  3. Carry it forward to checkout, either in the session (if the session persists that long) or written into order metadata as soon as an order or lead record is created.
  4. When you build the CAPI event payload for order_created, lead_created, or whatever event corresponds to the conversion, read the stored value back out and include it in the payload alongside the rest of the event data.
# Illustrative sketch, not a literal API contract
session.oppref = read_cookie("__oppref") or read_query_param("oppref")
# ... later, at order creation ...
order.metadata.oppref = session.oppref
# ... later, building the CAPI event ...
event_payload = {
  "id": event_id,
  "type": "order_created",
  "timestamp_ms": now_ms(),
  "data": { "oppref": order.metadata.oppref, ...other_fields },
  "action_source": "web",
  "source_url": order.landing_url
}

The exact field name and payload structure should follow OpenAI's Conversions API docs directly rather than this sketch — the point here is the architecture: capture early, persist through the funnel, forward explicitly at send time. Skipping the persistence step is the most common reason teams implement CAPI correctly in every other respect and still see attribution gaps specifically on server-side events.

Testing your attribution setup

Don't wait for a real ad campaign to discover a parameter-killer. Test the full chain deliberately:

  1. Get a tagged link. Use an ad preview link if you have access to one, or manually construct a URL to your landing page with an oppref value appended, matching the format your real ad destinations use.
  2. Click it and watch where you land. Note the final URL in your browser's address bar — did the parameter survive every redirect, or is it gone by the time the page finishes loading?
  3. Check the cookie. Open dev tools' Application (or Storage) tab and confirm __oppref was set with the value you expect.
  4. Check the event payload. Trigger a pixel event and inspect its payload — either in the Network tab or with the OpenAI Ads Pixel Helper Chrome extension, which shows live oaiq events as you browse — to confirm the attribution value is attached.
  5. If you're running CAPI, check the server side separately. Place a real test order and confirm the oppref value shows up in the server-side event payload, not just the client-side one. This step catches the persistence gap described above, which the pixel-side check alone won't reveal.

Run this test after any change to redirects, your consent tooling, or your URL structure — not just once at initial setup. A redirect rule that worked correctly in January can be replaced by a new one during an unrelated site update in June, and nothing about that change will look alarming unless you're specifically testing for parameter survival.


Attribution failures are quiet by design — nothing errors, nothing looks broken, and the conversions are genuinely happening. The only way to catch a stripped oppref parameter is to trace the actual path from ad click to event payload and confirm the value survives every hop along the way, rather than assuming it does because the rest of your tracking looks healthy.

Want this done for you?

Fixed-scope setup, tested end-to-end and documented.

Explore the serviceTake the free audit