# Shopify

Add ProductLense to a Shopify theme in layout/theme.liquid and identify logged-in customers with Liquid.

On Shopify, the script goes in your theme's `layout/theme.liquid`, just before the closing head tag, so it runs on every storefront page. Then connect Shopify as a billing source so paid orders and refunds are attributed to the channel that brought each buyer.

## Add the script

1. Copy your site id from Settings → Sites in the ProductLense dashboard.
2. In Shopify admin, open Online Store → Themes → … → Edit code → `layout/theme.liquid`.
3. Paste the snippet just before `</head>`, replacing `SITE_ID`, and save.

```liquid title="layout/theme.liquid" {2}
  <script>window.productlense=window.productlense||function(){(window.productlense.q=window.productlense.q||[]).push(arguments)}</script>
  <script defer data-site="SITE_ID" src="https://api.productlense.app/a.js"></script>
</head>
```

Add both your custom domain and your `myshopify.com` domain as hostnames of the site in ProductLense if shoppers reach both.

## Identify logged-in customers

Identify logged-in customers with their Shopify customer id, and copy the same id into a cart attribute named `pl_user_id`. Shopify keeps cart attributes on the order as note attributes, and the Shopify connector reads `pl_user_id` from them, so the order and the identified visitor meet on that id.

```liquid title="layout/theme.liquid" {4,7-11}
{% if customer %}
  {% assign pl_uid = customer.id | append: '' %}
  <script>
    window.productlense('identify', '{{ pl_uid }}');
    {% if cart.attributes.pl_user_id != pl_uid %}
      fetch('/cart/update.js', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ attributes: { pl_user_id: '{{ pl_uid }}' } }),
      });
    {% endif %}
  </script>
{% endif %}
```

> [!IMPORTANT]
> Theme scripts do not run on Shopify's checkout pages. ProductLense sees the storefront visit, and the order arrives from the Shopify connection. Orders from shoppers who never log in carry no `pl_user_id` and stay unattributed unless their customer record matches an identified visitor some other way; see [how payments are attributed](/docs/revenue/attribution).

## Connect orders

Follow [Connect Shopify](/docs/revenue/shopify) to create a custom app with read-only scopes and register the webhooks. ProductLense backfills 12 months of paid orders.

## Verify your installation

1. Open your storefront in a normal browser window.
2. Open the Live page in the ProductLense dashboard. Your visit appears within a few seconds.
3. In the browser's developer tools, the Network tab shows a `POST` to `https://api.productlense.app/api/e` with status `204`.

A password-protected store still loads the script for visitors who enter the password. Ad blockers in your own browser may block the request. If the visit does not appear, follow [Verify your installation](/docs/install/verify).
