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

# Connect Shopify

> Create a Shopify custom app with the required scopes and connect your store to OpenCX.

export const ShopifyFlow = () => {
  const BEAM_COLOR = "#22c55e";
  const renderBeam = ({id, d, duration = 2.8, delay = 0, reverse = false}) => {
    const values = reverse ? {
      x1: "110%;-10%",
      x2: "120%;0%"
    } : {
      x1: "-10%;110%",
      x2: "0%;120%"
    };
    return <g key={id}>
        <path d={d} stroke="currentColor" strokeOpacity="0.18" strokeWidth="1.5" fill="none" strokeLinecap="round" />
        <path d={d} stroke={`url(#${id})`} strokeWidth="2" fill="none" strokeLinecap="round" />
        <defs>
          <linearGradient id={id} gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="0">
            <stop offset="0%" stopColor={BEAM_COLOR} stopOpacity="0" />
            <stop offset="45%" stopColor={BEAM_COLOR} stopOpacity="1" />
            <stop offset="55%" stopColor={BEAM_COLOR} stopOpacity="1" />
            <stop offset="100%" stopColor={BEAM_COLOR} stopOpacity="0" />
            <animate attributeName="x1" values={values.x1} dur={`${duration}s`} begin={`${delay}s`} repeatCount="indefinite" />
            <animate attributeName="x2" values={values.x2} dur={`${duration}s`} begin={`${delay}s`} repeatCount="indefinite" />
          </linearGradient>
        </defs>
      </g>;
  };
  const OCX_X = 180, API_X = 440, DATA_X = 720;
  const MID = 180, R = 44;
  const dataTypes = [{
    key: "orders",
    label: "Orders",
    detail: "status · shipping",
    y: 90
  }, {
    key: "products",
    label: "Products",
    detail: "metadata · variants",
    y: 180
  }, {
    key: "customers",
    label: "Customers",
    detail: "email match · history",
    y: 270
  }];
  const b1 = `M ${OCX_X + R},${MID} L ${API_X - 40},${MID}`;
  const dataBeams = dataTypes.map((d, i) => ({
    id: `shop-d-${i}`,
    d: `M ${DATA_X - 70},${d.y} C ${DATA_X - 70 - 40},${d.y} ${API_X + 40 + 40},${MID} ${API_X + 40},${MID}`,
    delay: i * 0.4
  }));
  return <div className="zendesk-flow not-prose my-8 w-full">
      <div className="zendesk-flow-frame relative w-full overflow-hidden rounded-md border border-black/10 bg-white px-4 py-6 dark:border-white/10 dark:bg-zinc-950">
        <div className="zendesk-flow-grid pointer-events-none absolute inset-0" aria-hidden />
        <svg viewBox="0 0 880 360" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" className="relative z-[1] block w-full text-zinc-500 dark:text-zinc-400" role="img" aria-label="Shopify flow: OpenCX reads Orders, Products, and Customers via the Shopify Admin API — read-only">
          {renderBeam({
    id: "shop-1",
    d: b1,
    duration: 2.4,
    delay: 0,
    reverse: true
  })}
          {dataBeams.map(b => renderBeam({
    id: b.id,
    d: b.d,
    duration: 3.0,
    delay: b.delay,
    reverse: true
  }))}

          <text x={(OCX_X + API_X) / 2} y={MID - 18} textAnchor="middle" className="fill-zinc-500 dark:fill-zinc-400" style={{
    font: "500 11px ui-sans-serif, system-ui, sans-serif"
  }}>GraphQL · REST</text>

          {}
          <g className="fill-zinc-500 dark:fill-zinc-400">
            <polygon points={`${OCX_X + R + 4},${MID - 4} ${OCX_X + R - 2},${MID} ${OCX_X + R + 4},${MID + 4}`} fill={BEAM_COLOR} />
          </g>

          {}
          <g>
            <circle cx={OCX_X} cy={MID} r={R + 4} className="fill-none" stroke={BEAM_COLOR} strokeOpacity="0.25" strokeWidth="1.5">
              <animate attributeName="r" values={`${R + 2};${R + 12};${R + 2}`} dur="3.6s" repeatCount="indefinite" />
              <animate attributeName="stroke-opacity" values="0.35;0;0.35" dur="3.6s" repeatCount="indefinite" />
            </circle>
            <circle cx={OCX_X} cy={MID} r={R} className="fill-white stroke-black/10 dark:fill-zinc-900 dark:stroke-white/10" strokeWidth="1" />
            <foreignObject x={OCX_X - 34} y={MID - 18} width="68" height="36">
              <div className="flex h-full w-full items-center justify-center">
                <img src="/logo-light.svg" alt="" className="block h-full w-full object-contain dark:hidden" />
                <img src="/logo.svg" alt="" className="hidden h-full w-full object-contain dark:block" />
              </div>
            </foreignObject>
            <text x={OCX_X} y={MID + R + 22} textAnchor="middle" className="fill-zinc-700 dark:fill-zinc-200" style={{
    font: "600 12px ui-sans-serif, system-ui, sans-serif"
  }}>OpenCX</text>
            <text x={OCX_X} y={MID + R + 36} textAnchor="middle" className="fill-zinc-500 dark:fill-zinc-400" style={{
    font: "400 10.5px ui-sans-serif, system-ui, sans-serif"
  }}>AI actions · inbox sidebar</text>
          </g>

          {}
          <g>
            <polygon points={`${API_X - 40},${MID} ${API_X - 20},${MID - 28} ${API_X + 20},${MID - 28} ${API_X + 40},${MID} ${API_X + 20},${MID + 28} ${API_X - 20},${MID + 28}`} className="fill-white stroke-black/10 dark:fill-zinc-900 dark:stroke-white/10" strokeWidth="1" />
            <foreignObject x={API_X - 14} y={MID - 14} width="28" height="28">
              <div className="flex h-full w-full items-center justify-center">
                <img src="/images/integrations/shopify.svg" alt="" className="h-6 w-6 object-contain" />
              </div>
            </foreignObject>
            <text x={API_X} y={MID + 48} textAnchor="middle" className="fill-zinc-700 dark:fill-zinc-200" style={{
    font: "600 11.5px ui-sans-serif, system-ui, sans-serif"
  }}>Admin API</text>
            <text x={API_X} y={MID + 62} textAnchor="middle" className="fill-zinc-500 dark:fill-zinc-400" style={{
    font: "400 10px ui-sans-serif, system-ui, sans-serif"
  }}>custom app</text>
          </g>

          {}
          {dataTypes.map(d => <g key={d.key}>
              <rect x={DATA_X - 70} y={d.y - 22} width="150" height="44" rx="8" className="fill-white stroke-black/10 dark:fill-zinc-900 dark:stroke-white/10" strokeWidth="1" />
              <circle cx={DATA_X - 54} cy={d.y} r="7" fill={BEAM_COLOR} fillOpacity="0.18" stroke={BEAM_COLOR} strokeWidth="1.2" />
              <text x={DATA_X - 40} y={d.y - 3} className="fill-zinc-800 dark:fill-zinc-100" style={{
    font: "600 12px ui-sans-serif, system-ui, sans-serif"
  }}>{d.label}</text>
              <text x={DATA_X - 40} y={d.y + 10} className="fill-zinc-500 dark:fill-zinc-400" style={{
    font: "400 10.5px ui-sans-serif, system-ui, sans-serif"
  }}>{d.detail}</text>
            </g>)}

          <text x={DATA_X + 5} y={45} textAnchor="middle" className="fill-zinc-500 dark:fill-zinc-400" style={{
    font: "500 11px ui-sans-serif, system-ui, sans-serif"
  }}>Shopify data</text>
        </svg>
      </div>
    </div>;
};

The store connection gives OpenCX real-time access to your Shopify Admin API. Once connected, the AI can look up orders, search products, and your reps see customer metadata in the inbox sidebar.

<ShopifyFlow />

<Info>
  Setup takes about 10 minutes per store. You need admin access to both your Shopify store and your OpenCX organization.
</Info>

## Before you start

<AccordionGroup>
  <Accordion title="Shopify store with custom app support" icon="circle-check">
    Your Shopify plan must support custom app development. This is available on all current Shopify plans. If you don't see **Develop apps** in your Shopify admin, your store owner may need to enable it first.
  </Accordion>

  <Accordion title="Owner or admin in OpenCX" icon="key">
    Required to save integration settings in [Settings → Integrations](https://platform.open.cx/settings/integrations).
  </Accordion>
</AccordionGroup>

<Warning>
  **Disable order auto-archival before connecting.** Archived orders are not queryable through the Shopify API. The AI will not be able to look up archived orders.

  In your Shopify admin, go to **Settings → General → Order processing** and uncheck **Automatically archive the order**.

  <video autoPlay muted loop controls className="w-full" src="https://mintcdn.com/openchat/QQBUZEMVWs_GKqcv/videos/shopify/disable-auto-archival.mp4?fit=max&auto=format&n=QQBUZEMVWs_GKqcv&q=85&s=64ff50ac016778fb72913ff4b705e990" data-path="videos/shopify/disable-auto-archival.mp4" />
</Warning>

## Setup

<Steps>
  <Step title="Enable custom app development">
    In your Shopify admin, go to **Settings → Apps and sales channels → Develop apps**. You can also type *"Build custom apps"* in the search bar.

    Click **Allow custom app development** and confirm.
  </Step>

  <Step title="Create a custom app">
    Click **Create an app**. Name it `OpenCX` (or anything recognizable), then click **Create app**.

    <video autoPlay muted loop controls className="w-full" src="https://mintcdn.com/openchat/QQBUZEMVWs_GKqcv/videos/shopify/init-custom-app.mp4?fit=max&auto=format&n=QQBUZEMVWs_GKqcv&q=85&s=db2f988735c52a23826f62b27e77cc26" data-path="videos/shopify/init-custom-app.mp4" />
  </Step>

  <Step title="Configure Admin API scopes">
    Click **Overview → Configure Admin API Scopes** (or **Configuration → Admin API integration → Configure**).

    Enable the following scopes:

    | Scope            | Purpose                                |
    | ---------------- | -------------------------------------- |
    | `read_orders`    | Order lookup by order number           |
    | `read_products`  | Product catalog search                 |
    | `read_customers` | Customer metadata in the inbox sidebar |

    Click **Save**.

    <video autoPlay muted loop controls className="w-full" src="https://mintcdn.com/openchat/QQBUZEMVWs_GKqcv/videos/shopify/configure-scopes.mp4?fit=max&auto=format&n=QQBUZEMVWs_GKqcv&q=85&s=d31c0055e5196ea7882c1439bfcb51b8" data-path="videos/shopify/configure-scopes.mp4" />
  </Step>

  <Step title="Install the app and reveal the token">
    Go to **API Credentials → Access tokens** and click **Install app**. Confirm by clicking **Install** in the dialog.

    Click **Reveal token once** to display the <Tooltip tip="A long-lived credential that authenticates API requests to your store. Cannot be viewed again after you leave this page.">Admin API access token</Tooltip>. Copy it immediately.

    <Warning>
      The token is shown **only once**. If you lose it, you must uninstall and reinstall the app to generate a new one. Treat it like a password.
    </Warning>
  </Step>

  <Step title="Copy your Shopify domain">
    Your Shopify domain is the `*.myshopify.com` address for your store (e.g. `example.myshopify.com`). You can find it in the top-left corner of the **Settings** section in your Shopify admin.

    <video autoPlay muted loop controls className="w-full" src="https://mintcdn.com/openchat/QQBUZEMVWs_GKqcv/videos/shopify/install-custom-app.mp4?fit=max&auto=format&n=QQBUZEMVWs_GKqcv&q=85&s=be57412a29fdfc0af71ce8099ef07538" data-path="videos/shopify/install-custom-app.mp4" />
  </Step>

  <Step title="Save credentials in OpenCX">
    In your [OpenCX dashboard](https://platform.open.cx/settings/integrations), go to **Settings → Integrations** and find **Shopify**.

    | Field              | Value                                                                                               |
    | ------------------ | --------------------------------------------------------------------------------------------------- |
    | **Shopify domain** | Your `*.myshopify.com` domain. Include `.myshopify.com` — do not use your custom storefront domain. |
    | **Access token**   | The Admin API access token you copied in the previous step.                                         |

    Click **Save**. OpenCX validates the token and checks that the required scopes are granted before saving.
  </Step>

  <Step title="Verify the connection">
    After saving, open a conversation in the [inbox](https://platform.open.cx/inbox) where the contact's email matches a customer in your Shopify store. The sidebar should display the customer's profile and order history.

    If the sidebar is empty, check [Troubleshooting](/integrations/shopify/troubleshooting).
  </Step>
</Steps>

## Adding more stores

You can connect multiple Shopify stores to the same OpenCX organization. Each store has its own domain and access token.

In [Settings → Integrations](https://platform.open.cx/settings/integrations) → Shopify, click **Add Another Store** and repeat the setup steps above for each additional store. The AI routes lookups to the correct store automatically.

<Note>
  For multi-store setups, consider using **order number prefixes** (e.g. `UK-1001`, `DE-1002`) in your Shopify stores. This helps the AI identify which store an order belongs to when a customer provides their order number.
</Note>

## Rotating the access token

If a token is compromised or needs rotation:

1. In your Shopify admin, uninstall the custom app.
2. Reinstall it to generate a new token.
3. Update the token in [Settings → Integrations](https://platform.open.cx/settings/integrations) → Shopify.

The old token stops working immediately on uninstall.

## Disconnecting

In OpenCX, open [Settings → Integrations](https://platform.open.cx/settings/integrations) → Shopify and delete the store connection. Then in your Shopify admin, uninstall the custom app if you no longer need it.

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="AI Actions" icon="robot" href="/integrations/shopify/ai-actions">
    What the AI can do with your store data and how to toggle actions.
  </Card>

  <Card title="Contact Metadata" icon="address-card" href="/integrations/shopify/contact-metadata">
    Customer and order data in the inbox sidebar.
  </Card>

  <Card title="Knowledge Base Sync" icon="book" href="/knowledge/sources/shopify/connect">
    Train the AI on your store pages, articles, and products.
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/integrations/shopify/troubleshooting">
    Connection errors, missing scopes, token issues.
  </Card>
</CardGroup>
