> ## Documentation Index
> Fetch the complete documentation index at: https://docs.traceten.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Shopify

> Attribute Shopify orders to AI-referred sessions.

## What this lets you do

Connect your Shopify store to Traceten and see which AI sources drive purchases, return customers, and revenue per order, not just store visits.

## Before you start

* A Traceten account with at least one site tracked.
* A Shopify store, and permission to create an app in the Shopify organization that owns it.
* The Traceten snippet installed on your Shopify store. See the [Shopify install guide](/install/shopify). Connect the store here first, then paste the snippet: connecting is what tells Traceten your storefront domain, so the tag you copy afterwards already has the right cookie setting on it.

## Create your Shopify app

You create the app, on your own store. Traceten never installs anything.

This is deliberate. An app you create is a custom app, which Shopify does not review, and which can read order data without a separate protected-customer-data request. An app we distribute would need both, and you would wait weeks for revenue attribution that works the same way at the end of it.

<Steps>
  <Step title="Create the app">
    Go to the [Shopify Dev Dashboard](https://dev.shopify.com/dashboard) and create a new app. Name it anything you like, "Traceten" is fine.
  </Step>

  <Step title="Grant three read scopes">
    Under **API access**, add:

    | Scope            | What Traceten does with it                                                                                                                                                                                         |
    | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
    | `read_orders`    | Reads paid orders, live and for the 60-day import                                                                                                                                                                  |
    | `read_customers` | Without it Shopify redacts the buyer's email on every order, and purchases made as a guest or on a different device stop matching                                                                                  |
    | `read_themes`    | Read-only access to your published theme. Traceten asks for it now so it can check the snippet is still installed for you later, without you having to come back and edit the app. Nothing reads your theme today. |

    Traceten requests no write access of any kind. Nothing it does can change an order, a product or a theme.
  </Step>

  <Step title="Set the webhook API version to 2025-10">
    Under the app's webhook settings, choose API version **2025-10**.
  </Step>

  <Step title="Release the app and install it on your store">
    Release the version, then install the app on the store you want to attribute. The app and the store have to be in the **same Shopify organization**, which they are when you create the app yourself.
  </Step>
</Steps>

## Connect it to Traceten

<Steps>
  <Step title="Open Integrations in the dashboard">
    Go to [app.traceten.com/dashboard](https://app.traceten.com/dashboard) and open **Settings → Integrations**. Pick **Shopify**.
  </Step>

  <Step title="Paste three fields">
    * **Store domain**: the `.myshopify.com` address from **Settings → Domains** in your Shopify admin, for example `my-store.myshopify.com`. Not your customer-facing domain.
    * **Client ID** and **Client Secret**: both are on your app's settings page in the Dev Dashboard.

    Traceten exchanges the two credentials for a short-lived access token when it needs one. That token is never written to our database, and is cached only as encrypted ciphertext for at most 23 hours before a fresh one is minted. Your Client Secret is encrypted before it is written down, and only its last four characters can ever be read back.
  </Step>

  <Step title="Click Connect">
    Traceten checks the credentials against your live store, registers the webhooks it needs, and imports your last 60 days of paid orders. This takes a few seconds; the import runs in the background.
  </Step>
</Steps>

### What connecting does to your store

Traceten registers five webhook subscriptions and nothing else. It creates no script tag, no theme file and no app block.

| Topic              | What Traceten does with it                                                                                                                                     |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `orders/paid`      | Attributes the order. This is the revenue.                                                                                                                     |
| `refunds/create`   | Subtracts the refunded amount from the source that earned it.                                                                                                  |
| `orders/cancelled` | Takes back the order. A cancelled Shopify order is void, not just closed.                                                                                      |
| `themes/publish`   | Registered for the theme check described above. Nothing acts on it yet.                                                                                        |
| `app/uninstalled`  | Registered so the subscription exists from day one. Nothing acts on it yet: removing the app stops the other webhooks, and you disconnect in Traceten as well. |

Every delivery is verified against your app's own Client Secret before it is read. Shopify signs with that secret, which is why there is no fourth field to paste.

## If the connection is refused

| What you see                                                             | What it means                                                                                                                                                                                                   |
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "Those credentials belong to an app in a different Shopify organization" | `client_credentials` only works when the app and the store are in the same organization. Create the app from the organization that owns this store.                                                             |
| "That app is missing read\_orders and read\_customers"                   | Add the scopes under **API access**, release the new version, and connect again. Traceten refuses rather than connecting: without `read_customers` the email match would fail silently on every guest checkout. |
| "This app does not have read\_themes"                                    | A warning, not a refusal. Revenue attribution is unaffected. Adding the scope later means editing your app and releasing a new version, which is why Traceten asks for it up front.                             |
| "Shopify has no store at that domain"                                    | Use the `.myshopify.com` address, not your customer-facing domain.                                                                                                                                              |

## How attribution works

When an order is paid:

1. Shopify sends an `orders/paid` webhook to Traceten.
2. Traceten looks up the session associated with the order using the `_traceten_sid` session cookie value, which is stored as order note attributes when the customer starts checkout.
3. If the session has an AI attribution, the order is marked with that source, confidence score, and order value.
4. The revenue appears in your dashboard under the attributed AI source.

An order that has been placed but not paid produces no revenue row. Traceten waits for payment.

### Refunds and net revenue

Your attributed revenue is **net of refunds**. When a refund is created in Shopify, Traceten subtracts it from the AI source the original order was attributed to.

* **The refund is dated on the day it was issued**, not the day of the original order. A past day's revenue figure never changes after the fact, and a day on which you refunded more than you took in reads as a negative number.
* **Conversion counts stay gross.** A refunded order still counts as a conversion. The money is reported separately as a **refunded** figure beside the net one.
* **A partial refund subtracts only the line items you returned.** The product breakdown follows: the returned SKUs lose their units and their revenue, and the rest of the order keeps both.
* **A cancelled order is the exception that does come back out in full.** `orders/cancelled` means the order itself is void, which is different from a subscription being cancelled elsewhere in Traceten.

## How the session is captured

When a customer visits your store, the Traceten snippet sets the `_traceten_sid` session cookie. When they proceed to checkout, the snippet captures the session ID and passes it through checkout to the order.

This happens automatically for standard Shopify themes. No additional configuration is required.

For headless Shopify stores, see the note below.

## Headless Shopify

If your storefront uses a custom frontend (Hydrogen, Next.js, or another framework) that calls the Shopify Storefront API or Admin API to create orders, you'll need to pass the session ID manually:

```typescript theme={null}
// When creating a cart or draft order, include the session ID as a note attribute
const cart = await shopify.cart.create({
  note_attributes: [
    {
      name: "_traceten_sid",
      value: document.cookie.match(/_traceten_sid=([^;]+)/)?.[1] ?? "",
    },
  ],
});
```

Traceten reads `_traceten_sid` from order note attributes if the standard cookie capture is not available.

## Revenue data

Attributed orders appear in your dashboard with:

* Order value, stored in the order's own currency and converted to USD at that day's rate (see [Currencies](/integrations/currencies))
* Orders from the last 60 days at the moment you connect. That is as far back as `read_orders` reaches; earlier orders are not available to any app without a separate Shopify approval.
* AI source and confidence score
* Order date and session entry page

## Using a processor we do not integrate with

Shopify, [Stripe](/integrations/stripe), [Lemon Squeezy](/integrations/lemonsqueezy), [Polar](/integrations/polar) and [Paddle](/integrations/paddle) have built-in integrations. [Dodo](/integrations/dodo) has a documented path with no server of yours required. For anything else, including Podia, Kajabi and your own checkout, send payments to the [Payment API](/api/payments) instead.

Do not do both for the same processor. If you connect Shopify here **and** post Shopify orders to the Payment API, every order is recorded twice and your revenue is overstated. The two paths deduplicate on different keys and cannot see each other. See [avoiding duplicate payments](/api/payments#avoiding-duplicate-payments).

## Cookies across two domains

A Shopify business often runs on two properties: content on `example.com`, the store on `shop.example.com`, or the reverse. AI assistants cite the content and the purchase happens on the store, so without a shared cookie those are two unrelated visitors and the AI touch is orphaned from the revenue it produced.

When you connect, Traceten reads the storefront domain Shopify reports and scopes your identity cookies to its registrable domain, so one person stays one person across both. See [Cookies across subdomains](/install/subdomains).

If your store still runs on `my-store.myshopify.com` with no custom domain of your own, this cannot be done, and Traceten says so on the card rather than pretending otherwise: `my-store.myshopify.com` and `example.com` are different registrable domains, and no cookie can span them. Connect a custom domain in Shopify, then reconnect here.

## Disconnecting Shopify

1. Go to **Settings → Integrations** in the dashboard.
2. Pick **Shopify**, then click **Disconnect**. Traceten deletes the five webhook subscriptions it created on your store.
3. Remove the app from your Shopify admin under **Settings → Apps and sales channels**.

Disconnecting stops future order attribution. Historical attributed orders remain in your Traceten data.
