> For the complete documentation index, see [llms.txt](https://doc.batch.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://doc.batch.com/integrations/marketing-platforms/how-to-integrate-batch-on-shopify-for-web-tracking.md).

# How to integrate Batch on Shopify for web tracking

This guide explains how to integrate the Batch Web SDK on a Shopify storefront to collect profile data and behavioral events without enabling Web Push.

### How it works

The Batch Web SDK can be added directly to your Shopify theme from:

**Shopify Admin → Online Store → Themes → Edit code → Layout → `theme.liquid`**

The SDK is initialized with Web Push disabled:

```javascript
batchSDK('setup', {
  apiKey: 'API_KEY',
  authKey: 'AUTH_KEY',
  push: false,
});
```

Replace `API_KEY` and `AUTH_KEY` with the keys from the relevant Batch project and environment.

With Web Push disabled, no Service Worker, VAPID key, or Web Push configuration is required.

Once initialized, Batch can collect behavioral events from visitors browsing the storefront, including anonymous visitors. When a visitor is identified, for example after logging in, you can associate their Shopify customer ID with their Batch profile using `identify()`.

This makes it possible to progressively build a customer journey from anonymous browsing to identified activity.

### Add Batch to your Shopify theme

Before modifying your production theme, we recommend duplicating it and implementing Batch on the duplicated version first.

Add the Batch JavaScript snippet before the closing `</body>` tag in `theme.liquid`:

```html
<script type="text/javascript">

(function(b,a,t,c,h,e,r){
  h='batchSDK';
  b[h]=b[h]||function() {
    (b[h].q=b[h].q||[]).push(arguments)
  };
  e=a.createElement(t),
  r=a.getElementsByTagName(t)[0];
  e.async=1;
  e.src=c;
  r.parentNode.insertBefore(e,r);
})(
  window,
  document,
  'script',
  'https://via.batch.com/v5/bootstrap.min.js'
);

batchSDK('setup', {
  apiKey: 'API_KEY',
  authKey: 'AUTH_KEY',
  push: false,
});

</script>
```

Once the SDK is initialized, you can use Shopify Liquid objects and storefront interactions to populate Batch profiles and track events.

### Identify logged-in customers

Shopify exposes the `customer` Liquid object when a customer is logged in.

You can use the Shopify customer ID as your Batch Custom User ID:

```javascript
batchSDK(async api => {
  const profile = await api.profile();

  {% if customer %}

  await profile.identify({
    customId: String({{ customer.id | json }})
  });

  {% endif %}
});
```

The `customer` object is `nil` for visitors who are not logged in. Identification therefore only occurs once Shopify knows the customer.

Events collected before identification remain associated with the Batch installation. When the visitor is later identified, the Custom User ID is associated with that installation.

{% hint style="warning" %}
Your Custom User ID strategy should remain consistent across your Batch integrations. If you already identify users in Batch through another channel or data source, use the same identifier rather than automatically using the Shopify customer ID.
{% endhint %}

### Enrich Batch profiles with Shopify data

Once a customer is identified, Shopify customer data can be used to enrich their Batch profile.

For example:

```javascript
await profile.edit(editor => {
  editor
    .setEmailAddress({{ customer.email | json }})
    .setEmailMarketingSubscription(
      {% if customer.accepts_marketing %}
        "subscribed"
      {% else %}
        "unsubscribed"
      {% endif %}
    )
    .setAttribute(
      "orders_count",
      {{ customer.orders_count | json }}
    )
    .setAttribute(
      "total_spent",
      {{ customer.total_spent | divided_by: 100.0 }}
    );
});
```

Common Shopify data that can be used includes:

| Shopify data                     | Batch destination  | Availability       |
| -------------------------------- | ------------------ | ------------------ |
| `customer.id`                    | Custom User ID     | Logged-in customer |
| `customer.email`                 | Email address      | Logged-in customer |
| `customer.accepts_marketing`     | Email subscription | Logged-in customer |
| `localization.language.iso_code` | Language           | Storefront         |
| `localization.country.iso_code`  | Region             | Storefront         |
| `customer.orders_count`          | Custom attribute   | Logged-in customer |
| `customer.total_spent`           | Custom attribute   | Logged-in customer |
| `customer.b2b?`                  | Custom attribute   | Logged-in customer |
| `customer.first_name`            | Custom attribute   | Logged-in customer |
| `customer.last_name`             | Custom attribute   | Logged-in customer |
| `customer.tags`                  | Array attribute    | Logged-in customer |
| `customer.metafields`            | Custom attributes  | Logged-in customer |

The exact attributes you send should be defined as part of your tagging plan according to the use cases you want to implement in Batch.

#### Use Batch reserved fields when available

Some data has dedicated fields in Batch and should not be stored as generic custom attributes.

| Data                         | Batch implementation              |
| ---------------------------- | --------------------------------- |
| Custom User ID               | `profile.identify()`              |
| Email address                | `setEmailAddress()`               |
| Email marketing subscription | `setEmailMarketingSubscription()` |
| Language                     | `setLanguage()`                   |
| Region                       | `setRegion()`                     |
| Other business data          | `setAttribute()` / `addToArray()` |

For example, language and region can be populated from Shopify localization:

```javascript
await profile.edit(editor => {
  editor
    .setLanguage({{ localization.language.iso_code | json }})
    .setRegion({{ localization.country.iso_code | json }});
});
```

### Track storefront events

The Batch Web SDK can also track behavioral events occurring on the Shopify storefront.

The exact events and attributes to collect depend on your tagging plan. Typical ecommerce events include:

| Event                   | Example attributes                       |
| ----------------------- | ---------------------------------------- |
| `page_viewed`           | Page type, URL                           |
| `product_viewed`        | Product ID, type, vendor, price, variant |
| `collection_viewed`     | Collection ID, product count             |
| `search_submitted`      | Search term, results count               |
| `cart_viewed`           | Item count, cart value                   |
| `product_added_to_cart` | Product ID, variant ID, quantity, price  |

#### Example: track a product view

Liquid objects can be used to populate event attributes when the corresponding Shopify page is rendered:

```javascript
{% if request.page_type == "product" %}

{% assign current_variant = product.selected_or_first_available_variant %}

await api.trackEvent("product_viewed", {
  label: {{ product.title | json }},
  attributes: {
    product_id: String({{ product.id | json }}),
    product_type: {{ product.type | json }},
    vendor: {{ product.vendor | json }},
    price: {{ product.price | divided_by: 100.0 }},
    available: {{ product.available | json }},
    variant_id: String({{ current_variant.id | json }})
  }
});

{% endif %}
```

This is an example implementation. Adapt the event name and attributes to your Batch tagging plan.

#### Example: track add-to-cart interactions

Many Shopify themes add products to the cart dynamically without rendering a new page.

In those cases, the add-to-cart interaction needs to be tracked from JavaScript rather than Liquid page rendering.

For example, if the theme uses Shopify's `/cart/add` endpoint, you can detect successful add-to-cart requests and send an event to Batch:

```javascript
(function () {
  const originalFetch = window.fetch;

  window.fetch = function (...args) {
    const url = String(
      (args[0] && args[0].url) || args[0] || ""
    );

    const isAdd = url.includes("/cart/add");

    return originalFetch
      .apply(this, args)
      .then(response => {
        if (isAdd && response.ok) {
          response
            .clone()
            .json()
            .then(data => {
              batchSDK(api =>
                api.trackEvent("product_added_to_cart", {
                  label: data.product_title,
                  attributes: {
                    product_id: String(data.product_id),
                    variant_id: String(data.variant_id),
                    quantity: data.quantity,
                    price: data.final_price / 100
                  }
                })
              );
            })
            .catch(() => {});
        }

        return response;
      });
  };
})();
```

Shopify themes can implement cart interactions differently. Validate this behavior on your actual theme and adapt the tracking when necessary.

If your theme exposes its own add-to-cart JavaScript handler, tracking the event directly from that handler is preferable.

The same consideration applies to cart drawers: opening a cart drawer does not render the Shopify `/cart` page, so a `cart_viewed` event based only on Liquid page rendering will not be triggered.

### Important implementation considerations

#### Use Shopify's `json` filter

Whenever you inject a Liquid value into JavaScript, use Shopify's `json` filter:

```javascript
{{ customer.first_name | json }}
```

This ensures strings, special characters, booleans, and null values are correctly converted to JavaScript values.

#### Convert identifiers to strings

Shopify IDs are numeric. When using them as Batch Custom User IDs or other string identifiers, convert them to strings:

```javascript
String({{ customer.id | json }})
String({{ product.id | json }})
String({{ current_variant.id | json }})
```

#### Define your tagging plan before implementation

The examples in this guide illustrate data available from Shopify, but you do not need to collect all of it.

Before implementing profile attributes and events, define which data is required for your Batch use cases and make sure each value uses the appropriate Batch data type.

### Anonymous visitors and identification

Batch can collect storefront events before the visitor is identified.

For example, an anonymous visitor may generate:

```
page_viewed
    ↓
product_viewed
    ↓
product_added_to_cart
    ↓
login / identification
```

Once `identify()` is called, the Custom User ID is associated with the existing Batch installation.

This makes events particularly useful for use cases that start before the customer logs in.

Profile attributes associated with customer data, on the other hand, can only be populated when the relevant Shopify customer information is available.

### Shopify Checkout limitations

Shopify Checkout does not render the storefront's `theme.liquid` file.

As a result, the integration described in this guide cannot directly track checkout events such as:

* `checkout_started`
* `checkout_contact_info_submitted`
* `checkout_address_info_submitted`
* `checkout_shipping_info_submitted`
* `payment_info_submitted`
* `checkout_completed`

This limitation is particularly important for use cases such as abandoned-cart orchestration.

For example, knowing that a customer added a product to their cart is not sufficient to determine whether the cart was ultimately abandoned. You also need a reliable purchase or checkout-completed signal.

If this information is required by your use case, it must be collected separately and sent to Batch through an appropriate server-side integration using the Batch Profile API.

```
Shopify / backend
        ↓
Batch Profile API
        ↓
checkout_completed
```

{% hint style="warning" %}
Make sure the server-side integration uses the same Custom User ID strategy as the storefront integration so Batch can associate the event with the correct profile.
{% endhint %}

### Test your integration

Before publishing the modified Shopify theme, validate your implementation on a duplicated theme.

In particular, check that:

* the Batch SDK starts without errors;
* an Installation ID is generated;
* expected anonymous events are collected;
* product events contain the expected product and variant information;
* add-to-cart events fire once per interaction;
* cart behavior works with your actual Shopify theme;
* login correctly identifies the customer;
* reserved Batch fields are populated using the appropriate methods;
* custom attributes use the expected data types;
* events collected before login remain associated with the installation after identification;
* Batch is not already loaded elsewhere through the theme or another tag manager.

You can retrieve the Batch Installation ID from the browser console with:

```javascript
batchSDK(api => {
  api.getInstallationID().then(console.log);
});
```

Newly collected attributes and events may need to be enabled from the **Data** section of the Batch dashboard before they can be used.

### Related documentation

#### Batch

* [Web SDK JavaScript snippet](https://doc.batch.com/developer/sdk/web/getting-started/javascript-snippet)
* [Custom User ID](https://doc.batch.com/developer/sdk/web/profile-data/custom-user-id)
* [Email subscription](https://doc.batch.com/developer/sdk/web/profile-data/email-subscription)
* [Custom locale](https://doc.batch.com/developer/sdk/web/profile-data/custom-locale)
* [Profile attributes](https://doc.batch.com/developer/sdk/web/profile-data/attributes)
* [Events](https://doc.batch.com/developer/sdk/web/profile-data/events)
* [Profile API](https://doc.batch.com/developer/api/cep)

#### Shopify

* [Liquid API](https://shopify.dev/docs/api/liquid)
* [Customer object](https://shopify.dev/docs/api/liquid/objects/customer)
* [Product object](https://shopify.dev/docs/api/liquid/objects/product)
* [Collection object](https://shopify.dev/docs/api/liquid/objects/collection)
* [Cart object](https://shopify.dev/docs/api/liquid/objects/cart)
* [Standard events](https://shopify.dev/docs/api/web-pixels-api/standard-events)
* [Events and webhooks](https://shopify.dev/docs/apps/build/events-webhooks)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://doc.batch.com/integrations/marketing-platforms/how-to-integrate-batch-on-shopify-for-web-tracking.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
