Triangle Digital
Data layer

Shopify Data Layer: What It Is and How to Build One for GA4 Ecommerce

By Alessandro Colarossi, Founder, Triangle Digital · Published · 9 min read

Short answer

A Shopify data layer is a JavaScript array, window.dataLayer, that your store fills with structured details about what is happening (the product viewed, the cart, the order) so Google Tag Manager can pass the same clean data to GA4, Google Ads, Meta and other tags. Shopify does not ship one for GTM, so you build it: Liquid snippets in your theme for storefront pages and a Customer Events pixel for checkout, both pushing GA4-format ecommerce events like view_item, add_to_cart and purchase.

What is a data layer?

A data layer is a plain JavaScript array that sits between your website and your tags. Instead of every marketing tag scraping the page for a product name or price, your site pushes that information into the array once, in a predictable shape, and Google Tag Manager reads it.

The basic patternjs
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  event: 'view_item',
  ecommerce: {
    currency: 'USD',
    value: 49.0,
    items: [{ item_id: 'TEE-BLK-M', item_name: 'Everyday Tee', price: 49.0, quantity: 1 }]
  }
});

The event key is what GTM listens for. Each push with an event value can fire a Custom Event trigger, and everything else in the object becomes available to Data Layer Variables.

Why a Shopify data layer matters

  • One source of truth. GA4, Google Ads, Meta, TikTok and Pinterest all read the same values, so revenue and item numbers match across platforms.
  • Tags stop breaking when the theme changes. Tags that scrape CSS selectors fail when a theme update renames a class. A data layer does not care how the page looks.
  • It unlocks GA4 ecommerce reports. Product, cart and checkout funnels need the items array that GA4 expects.
  • Easier debugging. You can inspect window.dataLayer in the browser console or in GTM Preview and see exactly what was sent.

How Shopify changes the picture

Shopify gives you two places to produce data layer events, and a complete setup uses both:

Where each Shopify data layer event comes from
SourceRuns onGood for
Theme Liquid snippetStorefront pages (home, collection, product, cart)Page-level context: view_item_list, view_item, view_cart. Liquid knows the product, collection and cart objects.
Customer Events custom pixelStorefront and checkout, sandboxedInteractions and checkout: add_to_cart, remove_from_cart, begin_checkout, add_shipping_info, add_payment_info, purchase.

Because the theme and the pixel can both see storefront events, decide who owns each event so nothing is reported twice. The pixel side is covered in the Customer Events guide.

Use the GA4 ecommerce format

Push events in the structure GA4 documents for ecommerce. That way GA4 tags need almost no mapping, and platforms like Google Ads can reuse the same objects. These are the events a full Shopify store should send:

GA4 ecommerce events and where they come from on Shopify
GA4 eventFires whenTypical source on Shopify
view_item_listA collection or search results list is shownTheme snippet (collection page)
view_itemA product page is viewedTheme snippet (product page)
add_to_cartA product is added to the cartCustomer Events (product_added_to_cart)
remove_from_cartA product is removed from the cartCustomer Events (product_removed_from_cart)
view_cartThe cart is viewedCustomer Events (cart_viewed) or theme snippet
begin_checkoutCheckout startsCustomer Events (checkout_started)
add_shipping_infoShipping step is submittedCustomer Events (checkout_shipping_info_submitted)
add_payment_infoPayment step is submittedCustomer Events (payment_info_submitted)
purchaseOrder is completedCustomer Events (checkout_completed)
searchA site search is madeCustomer Events (search_submitted)

Example: a view_item snippet in Liquid

Create a snippet (Online Store → Themes → Edit code → Snippets → Add a new snippet) named data-layer, then include it with {% render 'data-layer' %} near the top of <head> in theme.liquid, above the GTM snippet. This example covers the product page. It is illustrative: the tagging packs ship a complete, tested version covering every storefront event.

snippets/data-layer.liquid (product page)liquid
{%- if request.page_type == 'product' -%}
<script>
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({ ecommerce: null }); // clear the previous ecommerce object
  window.dataLayer.push({
    event: 'view_item',
    ecommerce: {
      currency: {{ cart.currency.iso_code | json }},
      value: {{ product.selected_or_first_available_variant.price | divided_by: 100.0 }},
      items: [{
        item_id: {{ product.selected_or_first_available_variant.sku | default: product.id | json }},
        item_name: {{ product.title | json }},
        item_brand: {{ product.vendor | json }},
        item_category: {{ product.type | json }},
        item_variant: {{ product.selected_or_first_available_variant.title | json }},
        price: {{ product.selected_or_first_available_variant.price | divided_by: 100.0 }},
        quantity: 1
      }]
    }
  });
</script>
{%- endif -%}

Two details matter here. The | json filter safely escapes quotes in product titles, and ecommerce: null is pushed first so values from a previous event do not leak into the next one (Google recommends this when pushing ecommerce objects).

snippets/data-layer.liquid (collection page)liquid
{%- if request.page_type == 'collection' -%}
<script>
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({ ecommerce: null });
  window.dataLayer.push({
    event: 'view_item_list',
    ecommerce: {
      item_list_id: {{ collection.handle | json }},
      item_list_name: {{ collection.title | json }},
      items: [
        {%- for product in collection.products limit: 24 -%}
        {
          item_id: {{ product.selected_or_first_available_variant.sku | default: product.id | json }},
          item_name: {{ product.title | json }},
          price: {{ product.price | divided_by: 100.0 }},
          index: {{ forloop.index }}
        }{% unless forloop.last %},{% endunless %}
        {%- endfor -%}
      ]
    }
  });
</script>
{%- endif -%}

Reading the data layer in Google Tag Manager

  1. Create a Custom Event trigger whose event name matches the push, for example view_item.
  2. Create a GA4 Event tag with the same event name, tick Send Ecommerce data, and choose Data Layer as the source. GA4 then reads ecommerce.items, value and currency automatically.
  3. For other tags (Google Ads, Meta, TikTok), create Data Layer Variables such as ecommerce.value and ecommerce.items, and use them in the tag fields.
  4. Open Preview, trigger the event on your store, and confirm the data layer message and the tag firing in Tag Assistant.

Rules that prevent most data layer bugs

  • Send numbers as numbers. value: 49.0, not value: "$49.00". Strings with currency symbols break GA4 and Google Ads values.
  • Always include `currency` (ISO code like USD) on events that carry value.
  • Keep `item_id` consistent across every event and, for Google Ads remarketing, aligned with the IDs in your Merchant Center feed. Feeds created by Shopify's Google channel typically use a shopify_<country>_<productId>_<variantId> pattern, so check yours before choosing an ID scheme.
  • Clear the ecommerce object with { ecommerce: null } before each ecommerce push.
  • Define `window.dataLayer` before GTM loads so early pushes are not lost.
  • Use a unique `transaction_id` (the Shopify order ID) on purchase, so platforms can de-duplicate.

Want the full data layer without writing it?

The Shopify DIY Tagging Packs include the complete data layer snippet and Customer Events pixel, already mapped to the GA4 ecommerce event set and wired to a ready-to-import Google Tag Manager container. Pair this guide with the GTM setup walkthrough and the GA4 ecommerce guide.

Frequently asked questions

Does Shopify have a built-in data layer for Google Tag Manager?

No. Shopify exposes data through Liquid objects on the storefront and through Customer Events in checkout, but it does not create a GTM data layer for you. You build one with a theme snippet and a custom pixel, or use a pre-built pack.

What is dataLayer.push in Shopify?

It is the JavaScript call that adds an event or data object to window.dataLayer. Google Tag Manager watches the array and can fire tags when it sees a push containing an event key.

Where does the Shopify data layer code go?

Storefront data layer code goes in a theme snippet rendered from theme.liquid, above the GTM snippet. Checkout events are pushed from a custom pixel under Settings → Customer events.

Do I need a data layer if I use the Google & YouTube app?

The app does its own tracking and does not give you a data layer you control. If you want Google Tag Manager to manage tags, you need your own data layer. See the comparison.

Why is my GA4 ecommerce report empty?

Common causes are a missing items array, value sent as a string, no currency, or the purchase event only being installed in the theme and never reaching checkout. Check with the debugging guide.

Skip the build

Get a ready-to-import Shopify Google Tag Manager container

Shopify DIY Tagging Packs ship a tested GTM container, the Shopify data layer snippet, the Customer Events pixel and a step-by-step install guide. Own the container, no monthly fee, 30 minutes of setup support included.