Shopify Data Layer Structure | Blue Frog Docs

Shopify Data Layer Structure

Complete reference for Shopify's native data layer structure, events, and how to access them in Google Tag Manager.

Shopify Data Layer Structure

Shopify provides a native data layer that automatically populates with page, product, cart, and customer data. This data layer integrates seamlessly with Google Tag Manager (GTM).

Data Layer Overview

Shopify pushes events to window.dataLayer using standard ecommerce data layer format. GTM can access this data through variables and triggers.

How Shopify Data Layer Works

  1. Page loads → Shopify theme pushes initial data
  2. User interactions → Events pushed to data layer
  3. GTM listens → Captures events and variables
  4. Tags fire → Send data to analytics platforms

Global Data Layer Object

On every page load, Shopify pushes a base data layer object:

window.dataLayer = [{
  event: 'page_viewed',
  page: {
    pageType: 'home',        // home, collection, product, cart, etc.
    resourceType: 'home',
    resourceId: null
  },
  user: {
    customerId: null,         // null for guests, ID for logged-in
    customerEmail: null,
    customerFirstName: null,
    customerLastName: null,
    customerPhone: null,
    customerOrdersCount: 0,
    customerTotalSpent: '0.00'
  },
  cart: {
    currency: 'USD',
    totalPrice: 0,
    itemCount: 0
  }
}];

Page Types

The page.pageType value indicates the current page:

Page Type Description Example URL
home Homepage /
collection Collection/category page /collections/all
product Product detail page /products/example-product
cart Shopping cart /cart
search Search results /search?q=query
page Static page /pages/about
blog Blog listing /blogs/news
article Blog post /blogs/news/article-title
404 Not found Any invalid URL
password Password page Pre-launch password page

Accessing Page Type in GTM

Create Variable:

  • Type: Data Layer Variable
  • Data Layer Variable Name: page.pageType
  • Name: DLV - Page Type

Use in Triggers:

  • Fire tags only on specific page types
  • Example: Fire product tag only when page.pageType equals product

Shopify Data Layer Events

Shopify automatically fires these events:

1. page_viewed

Fires on every page load.

{
  event: 'page_viewed',
  page: {
    pageType: 'product',
    resourceType: 'product',
    resourceId: 1234567890
  },
  user: { /* user data */ },
  cart: { /* cart data */ }
}

GTM Trigger:

  • Type: Custom Event
  • Event name: page_viewed

2. product_viewed

Fires when customer views a product detail page.

{
  event: 'product_viewed',
  ecommerce: {
    currencyCode: 'USD',
    detail: {
      products: [{
        id: 1234567890,
        name: 'Example Product',
        price: '29.99',
        brand: 'Brand Name',
        category: 'Category Name',
        variant: 'Medium / Blue',
        sku: 'SKU-123'
      }]
    }
  }
}

GTM Variable (Product ID):

  • Type: Data Layer Variable
  • Data Layer Variable Name: ecommerce.detail.products.0.id
  • Name: DLV - Product ID

GTM Variable (Product Name):

  • Type: Data Layer Variable
  • Data Layer Variable Name: ecommerce.detail.products.0.name
  • Name: DLV - Product Name

3. collection_viewed

Fires on collection/category pages.

{
  event: 'collection_viewed',
  ecommerce: {
    currencyCode: 'USD',
    actionField: {
      list: 'Collection Name'
    },
    impressions: [{
      id: 1234567890,
      name: 'Product 1',
      price: '19.99',
      brand: 'Brand',
      category: 'Category',
      position: 1
    }, {
      id: 1234567891,
      name: 'Product 2',
      price: '24.99',
      brand: 'Brand',
      category: 'Category',
      position: 2
    }]
  }
}

Note: The impressions array may contain up to 50 products.

4. search_submitted

Fires when customer performs a search.

{
  event: 'search_submitted',
  search: {
    searchTerm: 'customer query'
  }
}

GTM Variable:

  • Type: Data Layer Variable
  • Data Layer Variable Name: search.searchTerm
  • Name: DLV - Search Term

5. product_added_to_cart

Fires when item is added to cart.

{
  event: 'product_added_to_cart',
  ecommerce: {
    currencyCode: 'USD',
    add: {
      products: [{
        id: 1234567890,
        name: 'Example Product',
        price: '29.99',
        brand: 'Brand Name',
        category: 'Category',
        variant: 'Medium / Blue',
        quantity: 1
      }]
    }
  }
}

GTM Variable (Added Product):

// Custom JavaScript Variable
function() {
  const dl = window.dataLayer || [];
  for (let i = dl.length - 1; i >= 0; i--) {
    if (dl[i].ecommerce && dl[i].ecommerce.add) {
      return dl[i].ecommerce.add.products;
    }
  }
  return [];
}

6. product_removed_from_cart

Fires when item is removed from cart.

{
  event: 'product_removed_from_cart',
  ecommerce: {
    currencyCode: 'USD',
    remove: {
      products: [{
        id: 1234567890,
        name: 'Example Product',
        price: '29.99',
        quantity: 1
      }]
    }
  }
}

7. checkout_started (Shopify Plus Only)

Fires when checkout begins (only on Plus stores in checkout.liquid).

{
  event: 'checkout_started',
  ecommerce: {
    currencyCode: 'USD',
    checkout: {
      actionField: {
        step: 1
      },
      products: [{
        id: 1234567890,
        name: 'Example Product',
        price: '29.99',
        quantity: 1
      }]
    }
  }
}

8. checkout_completed

Fires on order confirmation page (all stores).

{
  event: 'checkout_completed',
  ecommerce: {
    currencyCode: 'USD',
    purchase: {
      actionField: {
        id: 'ORDER-123',
        affiliation: 'Shop Name',
        revenue: '59.98',
        tax: '5.00',
        shipping: '10.00'
      },
      products: [{
        id: 1234567890,
        name: 'Example Product',
        price: '29.99',
        quantity: 2
      }]
    }
  }
}

User Data

Customer information available in data layer (when logged in):

{
  user: {
    customerId: 1234567890,
    customerEmail: 'customer@example.com',
    customerFirstName: 'John',
    customerLastName: 'Doe',
    customerPhone: '+15551234567',
    customerOrdersCount: 5,
    customerTotalSpent: '299.95',
    customerTags: ['VIP', 'Newsletter']
  }
}

GTM Variables:

Customer ID:

  • Data Layer Variable Name: user.customerId
  • Name: DLV - Customer ID

Customer Email (hashed recommended):

  • Data Layer Variable Name: user.customerEmail
  • Name: DLV - Customer Email

Customer Lifetime Value:

  • Data Layer Variable Name: user.customerTotalSpent
  • Name: DLV - Customer LTV

Cart Data

Current cart information:

{
  cart: {
    currency: 'USD',
    totalPrice: 89.97,
    itemCount: 3,
    items: [{
      productId: 1234567890,
      variantId: 9876543210,
      name: 'Example Product',
      price: 29.99,
      quantity: 3
    }]
  }
}

GTM Variables:

Cart Total:

  • Data Layer Variable Name: cart.totalPrice
  • Name: DLV - Cart Total

Cart Item Count:

  • Data Layer Variable Name: cart.itemCount
  • Name: DLV - Cart Item Count

Creating GTM Variables

Method 1: Data Layer Variables (Simple)

For simple values that exist directly in data layer:

  1. Variables → New
  2. Variable Type: Data Layer Variable
  3. Data Layer Variable Name: Enter the path (e.g., page.pageType)
  4. Data Layer Version: Version 2
  5. Name: Give it a descriptive name (e.g., DLV - Page Type)

Method 2: Custom JavaScript (Complex)

For values that need processing or extraction:

// Variable: Get Product Items Array for GA4
function() {
  const dl = window.dataLayer || [];

  // Find most recent product_viewed event
  for (let i = dl.length - 1; i >= 0; i--) {
    if (dl[i].ecommerce && dl[i].ecommerce.detail) {
      const products = dl[i].ecommerce.detail.products;

      // Transform to GA4 format
      return products.map(function(p) {
        return {
          item_id: p.id,
          item_name: p.name,
          item_brand: p.brand || '',
          item_category: p.category || '',
          item_variant: p.variant || '',
          price: parseFloat(p.price),
          quantity: 1
        };
      });
    }
  }

  return [];
}

Method 3: Lookup Tables

For mapping Shopify values to custom values:

  1. Variable Type: Lookup Table
  2. Input Variable: \{\{DLV - Page Type\}\}
  3. Mappings:
    • productProduct Detail
    • collectionCategory
    • cartShopping Cart
  4. Default Value: Other

Common GTM Triggers for Shopify

All Pages Trigger

  • Type: Page View - All Pages
  • Use for: GA4 config tag, pageview events

Product Page Trigger

  • Type: Page View - DOM Ready
  • Condition: Page Type equals product
  • Use for: Product-specific tags

Product Viewed Event Trigger

  • Type: Custom Event
  • Event name: product_viewed
  • Use for: GA4 view_item event

Add to Cart Trigger

  • Type: Custom Event
  • Event name: product_added_to_cart
  • Use for: GA4 add_to_cart, Meta Pixel AddToCart

Purchase Trigger

  • Type: Custom Event
  • Event name: checkout_completed
  • Use for: GA4 purchase, Meta Pixel Purchase

Theme-Specific Variations

Dawn Theme (Shopify 2.0)

Dawn and OS 2.0 themes have full data layer support out of the box.

Older Themes (Legacy)

Some older themes may have:

  • Incomplete data layer implementation
  • Different variable names
  • Missing events

Fix: Update theme or manually implement missing events.

Custom Themes

If your theme doesn't populate the data layer:

// Add to theme.liquid to manually push product data
{% if template.name == 'product' %}
<script>
  window.dataLayer = window.dataLayer || [];
  dataLayer.push({
    event: 'product_viewed',
    ecommerce: {
      currencyCode: '{{ cart.currency.iso_code }}',
      detail: {
        products: [{
          id: '{{ product.id }}',
          name: '{{ product.title | escape }}',
          price: '{{ product.selected_or_first_available_variant.price | money_without_currency }}',
          brand: '{{ product.vendor | escape }}',
          category: '{{ product.type | escape }}',
          variant: '{{ product.selected_or_first_available_variant.title | escape }}'
        }]
      }
    }
  });
</script>
{% endif %}

Debugging Data Layer

Console Commands

View entire data layer:

console.table(window.dataLayer);

Find specific event:

window.dataLayer.filter(obj => obj.event === 'product_viewed');

Monitor new pushes:

const originalPush = window.dataLayer.push;
window.dataLayer.push = function() {
  console.log('New Data Layer Push:', arguments[0]);
  originalPush.apply(window.dataLayer, arguments);
};

GTM Preview Mode

  1. Enable Preview in GTM
  2. Navigate to your Shopify store
  3. Click Data Layer tab in Tag Assistant
  4. Inspect each data layer push
  5. Verify values populate correctly

Best Practices

1. Don't Modify Shopify's Native Events

Shopify's data layer is automatically populated. Avoid overwriting these events unless necessary.

2. Add Custom Events Carefully

If adding custom events, use unique event names:

// Good
dataLayer.push({event: 'custom_newsletter_signup'});

// Bad (conflicts with Shopify)
dataLayer.push({event: 'product_viewed'});

3. Handle Missing Data

Always provide fallback values:

// GTM Custom JavaScript Variable
function() {
  return {{DLV - Product Brand}} || 'Unknown Brand';
}

4. Normalize Currency

Ensure currency values are numeric:

{{ price | money_without_currency }}  // Good: 19.99
{{ price }}                            // Bad: $19.99

5. Respect Customer Privacy

Hash or remove PII before sending to third parties:

// Hash email before sending
function hashEmail(email) {
  // Use SHA-256 or similar
  return btoa(email); // Simple encoding (use proper hashing)
}

Troubleshooting

Data Layer is Empty

Check:

  • GTM installed correctly in theme
  • Modern theme with data layer support
  • No JavaScript errors blocking execution

Variables Return Undefined

Check:

  • Variable name matches exact data layer path
  • Event has fired before variable is accessed
  • Data layer version set to Version 2

Events Fire Multiple Times

Cause: Theme JavaScript or apps pushing duplicate events.

Fix: Debug with console to identify source, remove duplicates.

Next Steps

For general data layer concepts, see Data Layer Guide.

// SYS.FOOTER