# Shopify orders with ChatGPT as the source: how to read that label

> Shopify derives an order's source from the visit's referrer and landing page. What that proves, why it goes missing by checkout, and how to reconcile it.

Canonical: https://convrail.com/blog/shopify-order-source-chatgpt/

Shopify's source label on an order is derived, not declared: it comes from the referrer and landing page of the session in which the order was placed, exposed in the API as `referring_site`, `landing_site` and the order's customer journey. It proves that the session began from a ChatGPT link. It does not, on its own, say whether that link was an ad, and it disappears whenever the referrer does.

## Where the label comes from

Shopify records two facts about the visit that produced an order. The [REST Order resource](https://shopify.dev/docs/api/admin-rest/latest/resources/order) defines `landing_site` as "The URL for the page where the buyer landed when they entered the shop." and `referring_site` as "The website where the customer clicked a link to the shop." The same page maps both to their GraphQL equivalents on the `CustomerVisit` object, `landingPage` and `referrerUrl`, and marks the older `landingPageUrl` and `referrerUrl` fields directly on the GraphQL `Order` as deprecated.

The [CustomerVisit object](https://shopify.dev/docs/api/admin-graphql/latest/objects/CustomerVisit) is where the richer picture lives. Shopify describes it as "A customer's session on the online store. Tracks how the Customer arrived at the store, including the landing page, referral source, and any associated marketing campaigns." Its fields are the raw material of every source label you will ever see in the admin:

| Field | Shopify's definition | What it tells you about ChatGPT |
| --- | --- | --- |
| `landingPage` | "URL of the first page the customer landed on for the session." | Whether the URL carried `oppref` or UTM parameters |
| `referrerUrl` | "Webpage where the customer clicked a link that sent them to the online store." | Whether the click came from chatgpt.com |
| `source` | "Source from which the customer visited the store, such as a platform (Facebook, Google), email, direct, a website domain, QR code, or unknown." | Shopify's own classification of that referrer |
| `utmParameters` | "A set of UTM parameters gathered from the URL parameters of the referrer." | Anything you or a link builder appended |
| `referralCode` | "Marketing referral code from the link that the customer clicked to visit the store. Supports the following URL attributes: ref, source, or r." | Rarely relevant for ChatGPT traffic |
| `occurredAt` | "The date and time when the customer's session occurred." | How far the click sits from the order |

Visits are grouped per order in the [CustomerJourneySummary](https://shopify.dev/docs/api/admin-graphql/latest/objects/CustomerJourneySummary), which "Tracks session data, attribution sources, and the timeline from first visit to purchase conversion." It exposes a `firstVisit` ("The customer's first session going into the shop."), a `lastVisit` ("The last session before an order is made."), a `daysToConversion` and a `momentsCount`. The [Order object](https://shopify.dev/docs/api/admin-graphql/latest/objects/Order) summarizes the whole thing as "The customer's visits and interactions with the online store before placing the order."

One field that is often mistaken for the source is `source_name`. It is not about traffic. Shopify defines it as "The source channel that the order is attributed to. Set this to the handle of an order attribution definition configured for your sales channel app, such as `youtube` or `channel:amazon-us`." For an ordinary online store order it reads `web`, whatever brought the shopper there. If you are filtering orders by `source_name` hoping to find ChatGPT, you are looking at the wrong column.

## Why the referrer is often gone by checkout

The referrer is a browser header. It is present on the request that follows a click, when the linking site and the browser both allow it to be sent, and it is captured once for the session. Nothing about it survives a change of session.

That is why the same shopper can produce two very different orders. Someone who reads a ChatGPT answer, clicks the product link and buys in the same sitting leaves a `referrerUrl` on chatgpt.com and a `landingPage` that may still carry parameters. Someone who reads the same answer, closes the tab, and comes back that evening by typing your domain starts a new session whose source Shopify can only record as "direct" or "unknown", the two catch-all values in its own definition of `source`. The recommendation happened; the evidence did not travel.

There is also a timing detail worth knowing if you consume orders by webhook. The `CustomerJourneySummary` has a `ready` field, "Whether the attributed sessions for the order have been created yet.", and its `momentsCount` "Returns null if the order is still in the process of being attributed." Shopify assembles the journey after the order exists. A connector that reads the journey the instant the `orders/paid` webhook fires may see an unfinished picture; reading `landing_site` and `referring_site` on the order itself, and re-checking the journey later, is the safer pattern.

## What `oppref` and UTM parameters prove

The referrer tells you where the click came from. Parameters on the landing URL tell you what kind of click it was.

The strongest signal is `oppref`. The [OpenAI Measurement Pixel reference](https://developers.openai.com/ads/measurement-pixel) states that the pixel "captures `oppref` from the landing page URL" and "stores `oppref` in a first-party `__oppref` cookie so later page views can reuse it." The [Conversions API reference](https://developers.openai.com/ads/conversions-api) describes the same value as "An opaque, OpenAI-provided attribution identifier." It is appended by ChatGPT Ads to the landing URL of an ad click, and by nothing else. When `landing_site` contains `oppref=<id>`, the session began from a paid click, full stop. Because it is on the URL, Shopify records it whether or not the referrer header made it through.

UTM parameters are weaker because anyone can write them. They prove that a link carrying those parameters was clicked; they prove nothing about who built the link. If your feed URLs include a medium of your own (OpenAI's feed best practices recommend adding feed-specific parameters such as `utm_medium=feed` to the `url` field), a `utm_source=chatgpt` with that medium is good evidence of an organic product result. We have not found an official OpenAI page that documents a fixed set of UTM parameters appended to organic ChatGPT links, so treat any UTM you did not put there yourself as informative rather than authoritative.

The referrer, finally, proves a click from chatgpt.com, chat.openai.com or openai.com, without saying whether the surface was an ad or an organic result. On its own it should read as organic, because paid clicks carry `oppref` and would have matched on that first.

## Convrail's decision table, and why the order of the rows matters

Convrail applies one fixed decision table to every order and stores the rule that fired, together with the value that matched, next to the attribution. The first matching row wins.

| Signal on the order | Verdict | Medium |
| --- | --- | --- |
| Landing URL contains `oppref=<id>` | ChatGPT | ads |
| `utm_source` is chatgpt, openai or chatgpt.com, and `utm_medium` is cpc, ppc, paid or ads | ChatGPT | ads |
| `utm_source` is chatgpt, openai or chatgpt.com, any other medium | ChatGPT | organic |
| Referrer is chatgpt.com, chat.openai.com or openai.com (or a subdomain) | ChatGPT | organic |
| None of the above | Other channel | not attributed |

The order encodes reliability. `oppref` is checked first because it is the only signal that cannot be produced by anything other than a ChatGPT Ads click, so a paid order is never downgraded to organic when the referrer was stripped or the shopper cleared cookies. Paid UTMs come second because they are deliberate, if forgeable. The referrer comes last because it is the most fragile and the least specific.

The evidence is what makes the table auditable. Every attributed order in Convrail carries three things: the medium (ads or organic), the method (which row matched) and the evidence (the actual `oppref` value, the UTM pair or the referrer host). The CSV export includes the same columns, so a merchant or an agency can re-derive every attribution from the raw fields without trusting the label. This is the same principle as the feature page on [attribution](/attribution/): a number is only worth reading when you can see the rule that produced it.

Convrail reads these signals as your platform recorded them on the order. On Shopify that is `landing_site` and `referring_site` from the order webhook; the web pixel also keeps `oppref` in the first-party cookie for 7 days so the identifier reaches the conversion events sent to OpenAI, which is how the Ads Manager and your dashboard end up describing the same click.

## Reconciling with the Ads Manager

Merchants who compare Shopify's ChatGPT-labelled orders with the conversions column in the Ads Manager usually find two numbers that disagree. Both can be right, because they count different things.

The Ads Manager counts conversions attributed to ad clicks. The [Insights reference](https://developers.openai.com/ads/api-reference/insights) states that "`conversions` is always equal to `click_through_conversions`; view-through conversions are a separate, supplemental metric and are not added to that total", and that "Click-through attribution follows the applicable configured click window." A conversion appears there when an `order_created` event with a matching `oppref` reached OpenAI, from the pixel or the Conversions API, inside the window.

Shopify's label counts sessions whose referrer or landing page pointed at ChatGPT, paid or organic, regardless of any window and regardless of whether an event ever reached OpenAI.

So the reconciliation is a subtraction, not a search for a bug:

1. Start from Convrail's attributed orders for the period, split by medium.
2. Remove the organic rows. The Ads Manager never counted them.
3. From the ads rows, expect a match for each order whose `order_created` event was sent inside the click window and accepted. Orders placed after the window, orders whose events were withheld for consent, and orders placed on a device where the `__oppref` cookie was absent will be in Convrail (the landing URL is evidence enough) but not in the Ads Manager.
4. What remains unexplained is worth investigating: an order with `oppref` on the landing URL, inside the window, with an accepted event, and no conversion in the Ads Manager points at a tracking gap. The failure modes are described in [ChatGPT Ads conversion optimization](/blog/chatgpt-ads-ocpc/).

Two caveats. Convrail dates an order by its order timestamp, while the Ads Manager reports by its own conventions, so day-level comparisons will drift at the edges; compare over a week rather than a day. And the Ads Manager conversions figure is a count of events, while Shopify counts orders; if your pipeline ever sent an order under two IDs, the Ads Manager side is the one that will be inflated.

## What attribution cannot prove

A source label, however carefully derived, is a last-touch, first-party observation. It answers "which link did this session start from", and only that.

It cannot see the shopper who asked ChatGPT for a comparison, was persuaded, and searched your brand name on Google an hour later. That order will read as Google, and it will be correct as a statement about the session while missing the cause. It cannot see the shopper who read the answer on a phone and bought on a laptop. It cannot distinguish a ChatGPT link forwarded in a group chat from a click inside ChatGPT, unless the URL carried a parameter.

It is also only as good as the platform's record. Shopify stores the landing page and referrer the browser sent; if a redirect chain, a consent tool or an app rewrote the URL before Shopify saw it, the evidence is whatever survived. Convrail does not fill these gaps with modelled numbers. It reports what it can evidence, labels each attributed order with its method, and leaves the weighting to you. How the organic and paid halves are then read together, including the ROAS definition, is the subject of [ChatGPT organic vs ChatGPT Ads](/blog/chatgpt-organic-vs-ads-attribution/).

## Common mistakes

- Filtering orders by `source_name` to find ChatGPT traffic. That field names the sales channel (`web`, `pos`, a channel app), never the referrer.
- Reading a chatgpt.com referrer as proof of an ad. Without `oppref` the session should be treated as organic.
- Reading the journey at webhook time and treating a null `momentsCount` as "no visits". Shopify may still be attributing the order; check `ready`.
- Comparing a single day of Shopify orders with a single day of Ads Manager conversions and concluding one side is broken.
- Stripping query parameters from landing URLs before storing them, for tidiness, and losing `oppref` with them.
- Trusting UTMs you did not create as if they were platform-issued identifiers.

## What to do next

If your Shopify admin shows ChatGPT orders and you want to know which ones you paid for, with the evidence per order and a CSV to check it, start with [Convrail attribution](/attribution/).