shopify-gtm-instrumentor

Helpers for sending standardized dataLayer events from a Shopify site

Usage no npm install needed!

<script type="module">
  import shopifyGtmInstrumentor from 'https://cdn.skypack.dev/shopify-gtm-instrumentor';
</script>

README

shopify-gtm-instrumentor

This package contains helper methods for sending standardized dataLayer events from Shopify to GTM. The API is modeled after the Enhanced Ecommerce Data Types and Actions.

It expects that you'll be using Shopify's own Enhanced Ecommerce support wherever possible (like for Checkout events or the initial Product Detail impression on Shopify hosted product pages).

This package is designed to supplement that integration for other uses cases like:

  • Firing client side Product Detail Impressions when interacting with a variant selector
  • Firing Add / Remove from Cart events from headless ecommerce implementations
  • Making it easy to create Enhanced Ecommerce dataLayer objects for supported actions.

Methods:

Setup

  1. Install the package
yarn add shopify-gtm-instrumentor
  1. Enable Shopify's Enhanced Ecommerce support

  2. Enable "Enable Enhanced Ecommerce Features" in GTM for your Google Analytics Settings.

  1. Include the checkout-snippet.liquid in your checkout.liquid.

Optional

Optional (GA4)

  • Set the disableEcommerceProperty option to true.
  • Import the ga4.json file into your GTM container to create tags for firing GA4 ecommerce events.
  • Per this article set myshopify.com as an "Unwanted Referral" in your data stream.

Usage

Instantiate this package like:

const gtmEcomm = new ShopifyGtmInstrumentor({
  currencyCode: 'EUR'
})

The constructor takes these options:

  • debug - If true, emits console.debug lines with the pushed events.
  • storeUrl - Your 'https://mystore.myshopify.com' style Shopify URL. Defaults to process.env.SHOPIFY_URL.
  • storefrontToken - A Storefront API token with permission to read products. Defaults to process.env.SHOPIFY_STOREFONT_TOKEN.
  • currencyCode - Defaults to USD.
  • disableEcommerceProperty - If true, removes the ecommerce property from the object which is used by UA Enhanced Commerce. You would enable this if you were using GA4 and want to use explicit tags, like those in ga4-tags.json
  • enableCheckoutEcommerceProperty - If true, adds ecommerce properties to Checkout and Purchase events. This is diabled by default because it's expected that you'd use Shopify's Google Analytics integration for this. However, if you are only using GA4 you may want to use this to support 3rd party GTM Tags that are expecting this property to exist.

Implemented methods described below:

Product Impressions

Used any time a product is displayed, like a product card.

gtmEcomm.productImpression(variantPayload, {
  el: null, // DOM Element
  list: null, // String
  position: null, // String
})
  • variantPayload - Either:

    • A Shopify numeric id, in which case the full variant is looked up via the Storefront API
    • A Shopify gid://shopify/ProductVariant/### style id, which will also be looked up via Storefront API
    • A Shopify ProductVariant object with product property. Not recommended since it requires particular fields to be present.
  • options - Supports the following keys

    • el - Optional DOM Element. If supplied, an IntersectionObserver will be attached to the element that triggers the event only once (and only once) the element has entered the viewport.
    • list - Optional name of the list or collection to which the product belongs.
    • position - Optional position in a list or collection. If el is provided and position is undefined, defaults to the index of the element relative to it's parent. 1-based.

Pushes an object to the dataLayer that looks like:

{
  event: 'Product Impression',
  firstOccurance: true,
  sku: 'sku-abc',
  variantId: '123',
  variantTitle: 'Black',
  variantImage: 'https://cdn.shopify.com/s/files/...',
  variantUrl: 'https://www.shop.com/product/great-t-shirt?variant=123',
  price: 18.99,
  compareAtPrice: 20.99,
  productId: '456',
  productTitle: 'Great T-Shirt',
  productVariantTitle: 'Great T-Shirt - Black',
  productType: 'Shirts',
  productVendor: 'Bukwild',
  productUrl: 'https://www.shop.com/product/great-t-shirt',
  ecommerce: {
    impressions: [
      {
        id: 'sku-abc',
        name: 'Great T-Shirt - Black',
        brand: 'Bukwild',
        category: 'Shirts',
        variant: 'Black',
        price: 18.99,
        list: 'Shirts Collection',
        position: 3
      }
    ]
  }
}

Product Clicks

gtmEcomm.productClick(variantPayload, options)

Used when a user clicks on a product, like to go to it's detail view.

  • variantPayload - Described above

  • options - Supports the following keys:

    • el - Optional DOM Element. If supplied, will be used to calulate the position by comparing the element's index relative it's parent.
    • list - Optional name of the list or collection to which the product belongs.
    • position - Optional position in a list or collection, 1-based.
    • clickEvent - Optionally pass the click event object here to wait to change page until the event has been pushed.

Pushes an object to the dataLayer that looks like:

{
  event: 'Product Click',
  firstOccurance: true,
  sku: 'sku-abc',
  variantId: '123',
  variantTitle: 'Black',
  variantImage: 'https://cdn.shopify.com/s/files/...',
  variantUrl: 'https://www.shop.com/product/great-t-shirt?variant=123',
  price: 18.99,
  compareAtPrice: 20.99,
  productId: '456',
  productTitle: 'Great T-Shirt',
  productVariantTitle: 'Great T-Shirt - Black',
  productType: 'Shirts',
  productVendor: 'Bukwild',
  productUrl: 'https://www.shop.com/product/great-t-shirt',
  ecommerce: {
    click: {
      actionField: { list: 'Shirts Collection'},
      products: [
        {
          id: 'sku-abc',
          name: 'Great T-Shirt - Black',
          brand: 'Bukwild',
          category: 'Shirts',
          variant: 'Black',
          price: 18.99,
          position: 3
        }
      ]
    }
  }
}

Product Detail Impressions

Used on product detail pages whenever the variant changes.

gtmEcomm.viewProductDetails(variantPayload)
  • variantPayload - See above

Pushes an object to the dataLayer that looks like:

{
  event: 'View Product Details',
  firstOccurance: true,
  sku: 'sku-abc',
  variantId: '123',
  variantTitle: 'Black',
  variantImage: 'https://cdn.shopify.com/s/files/...',
  variantUrl: 'https://www.shop.com/product/great-t-shirt?variant=123',
  price: 18.99,
  compareAtPrice: 20.99,
  productId: '456',
  productTitle: 'Great T-Shirt',
  productVariantTitle: 'Great T-Shirt - Black',
  productType: 'Shirts',
  productVendor: 'Bukwild',
  productUrl: 'https://www.shop.com/product/great-t-shirt',
  ecommerce: {
    detail: {
      products: [
        {
          id: 'sku-abc',
          name: 'Great T-Shirt - Black',
          brand: 'Bukwild',
          category: 'Shirts',
          variant: 'Black',
          price: 18.99
        }
      ]
    }
  }
}

The firstOccurance property will be true the first time this method is called in a given request and false for the remainder. You would use this when a product detail page is served by Shopify and the Shopify Enhanced Ecommerce integration will be firing the inital event but you will be firing additional events as a user interacts with a variant selector. For example:

Add / Remove from Cart

Used when products are added or removed from the cart.

gtmEcomm.addToCart(variantPayload, quantity)
gtmEcomm.removeFromCart(variantPayload, quantity)
  • variantPayload - See above
  • quantity - The quantity changed. So, if updating the quanity from 2 to 5, the value should be 3. If deleting a line item with a quantity of 2, you would use removeProductFromCart with a quantity of 2.

Pushes an object to the dataLayer that looks like:

{
  event: 'Add to Cart',
  firstOccurance: true,
  quantity: 1,
  sku: 'sku-abc',
  variantId: '123',
  variantTitle: 'Black',
  variantImage: 'https://cdn.shopify.com/s/files/...',
  variantUrl: 'https://www.shop.com/product/great-t-shirt?variant=123',
  price: 18.99,
  compareAtPrice: 20.99,
  productId: '456',
  productTitle: 'Great T-Shirt',
  productVariantTitle: 'Great T-Shirt - Black',
  productType: 'Shirts',
  productVendor: 'Bukwild',
  productUrl: 'https://www.shop.com/product/great-t-shirt',
  ecommerce: {
    add: {
      currencyCode: 'USD',
      products: [
        {
          id: 'sku-abc',
          name: 'Great T-Shirt - Black',
          brand: 'Bukwild',
          category: 'Shirts',
          variant: 'Black',
          price: 18.99,
          quantity: 1
        }
      ]
    }
  }
}

or like this

{
  event: 'Remove from Cart',
  firstOccurance: true,
  quantity: 1,
  sku: 'sku-abc',
  variantId: '123',
  variantTitle: 'Black',
  variantImage: 'https://cdn.shopify.com/s/files/...',
  variantUrl: 'https://www.shop.com/product/great-t-shirt?variant=123',
  price: 18.99,
  compareAtPrice: 20.99,
  productId: '456',
  productTitle: 'Great T-Shirt',
  productVariantTitle: 'Great T-Shirt - Black',
  productType: 'Shirts',
  productVendor: 'Bukwild',
  productUrl: 'https://www.shop.com/product/great-t-shirt',
  ecommerce: {
    remove: {
      currencyCode: 'USD',
      products: [
        {
          id: 'sku-abc',
          name: 'Great T-Shirt - Black',
          brand: 'Bukwild',
          category: 'Shirts',
          variant: 'Black',
          price: 18.99,
          quantity: 1
        }
      ]
    }
  }
}

See above for info on firstOccurance.

Cart Updated

Used to send the current checkout / cart state to GTM. This is not an explicit Enhanced Ecommerce event but many GTM want this data.

gtmEcomm.cartUpdated(checkoutOrCartPayload)
  • checkoutOrCartPayload - Either a Cart or Checkout ID that can be resolved by the Storefront API (recommended) or an object that is formed to look like one (like the window.CHECKOUT_LINE_ITEMS object, described below).

Pushes an object to the dataLayer that looks like:

{
  event: 'Cart Updated',
  firstOccurance: true,
  checkoutId: '789',
  checkoutUrl: 'https://www.shop.com/.../checkouts/...',
  subtotalPrice: 18.99,
  totalPrice: 18.99,
  lineItems: [
    {
      lineItemId: '456',
      quantity: 1,
      sku: 'sku-abc',
      variantId: '123',
      variantTitle: 'Black',
      variantImage: 'https://cdn.shopify.com/s/files/...',
      variantUrl: 'https://www.shop.com/product/great-t-shirt?variant=123',
      price: 18.99,
      compareAtPrice: 20.99,
      productId: '456',
      productTitle: 'Great T-Shirt',
      productVariantTitle: 'Great T-Shirt - Black',
      productType: 'Shirts',
      productVendor: 'Bukwild',
      productUrl: 'https://www.shop.com/product/great-t-shirt',
    }
  ]
}

Checkout

This would be triggered by each step of the checkout, like:

if (window.Shopify && window.Shopify.Checkout) {
  gtmEcomm.checkout(window.CHECKOUT_FOR_GTM_INSTRUMENTOR,
    window.Shopify.Checkout.step)
}

Currently, window.Shopify.Checkout.step resolves to:

  1. "contact_information"
  2. "shipping_method"
  3. "payment_method"
  4. "processing"
  5. "thank_you"
  6. undefined (becomes undefined on reload / order page)

The CHECKOUT_FOR_GTM_INSTRUMENTOR array is created by checkout-snippet.liquid (I couldn't find a way to query this besides outputting from liquid, would love to not couple it with a liquid snippet...)

This isn't designed to trigger the Enhanced Ecommerce purchase action; we're expecting Shopify's Enhanced Ecommerce integration to fire this. Instead, this event is designed to be useful for firing other conversion type tags from GTM.

{
  event: 'Checkout',
  firstOccurance: true,
  checkoutStep: `contact_information`
  checkoutId: '789',
  checkoutUrl: 'https://www.shop.com/.../checkouts/...',
  subtotalPrice: 18.99,
  totalPrice: 18.99,
  lineItems: [
    {
      lineItemId: '456',
      quantity: 1,
      sku: 'sku-abc',
      variantId: '123',
      variantTitle: 'Black',
      variantImage: 'https://cdn.shopify.com/s/files/...',
      variantUrl: 'https://www.shop.com/product/great-t-shirt?variant=123',
      price: 18.99,
      compareAtPrice: 20.99,
      productId: '456',
      productTitle: 'Great T-Shirt',
      productVariantTitle: 'Great T-Shirt - Black',
      productType: 'Shirts',
      productVendor: 'Bukwild',
      productUrl: 'https://www.shop.com/product/great-t-shirt',
    }
  ]
}

If enableCheckoutEcommerceProperty was set to true, the dataLayer will also include:

{
  ecommerce: {
    checkout: {
      actionField: {
        step: 'contact_information'
      },
      products: [
        {
          id: 'sku-abc',
          name: 'Great T-Shirt - Black',
          brand: 'Bukwild',
          category: 'Shirts',
          variant: 'Black',
          price: 18.99,
          quantity: 1
        }
      ]
    }
  }
}

Purchases

Should be triggered on the thank you page after checkout.

if (window.Shopify &&
  window.Shopify.Checkout &&
  window.Shopify.Checkout.step == 'thank_you') {
  gtmEcomm.purchase(window.CHECKOUT_FOR_GTM_INSTRUMENTOR)
}

Like Checkout, this isn't intended to replace Shopify's Enhannced Ecommerce support. It creates a payload like:

{
  event: 'Purchase',
  firstOccurance: true,
  checkoutId: '789',
  checkoutUrl: 'https://www.shop.com/.../checkouts/...',
  subtotalPrice: 18.99,
  totalPrice: 18.99,
  lineItems: [
    {
      lineItemId: '456',
      quantity: 1,
      sku: 'sku-abc',
      variantId: '123',
      variantTitle: 'Black',
      variantImage: 'https://cdn.shopify.com/s/files/...',
      variantUrl: 'https://www.shop.com/product/great-t-shirt?variant=123',
      price: 18.99,
      compareAtPrice: 20.99,
      productId: '456',
      productTitle: 'Great T-Shirt',
      productVariantTitle: 'Great T-Shirt - Black',
      productType: 'Shirts',
      productVendor: 'Bukwild',
      productUrl: 'https://www.shop.com/product/great-t-shirt',
    }
  ]
}

If enableCheckoutEcommerceProperty was set to true, the dataLayer will also include:

{
  ecommerce: {
    purchase: {
      actionField: {
        id: ''
        revenue: 18.99,
        tax: 0.00,
        shipping: 0.00,
        coupon: 'one,two'
      },
      products: [
        {
          id: 'sku-abc',
          name: 'Great T-Shirt - Black',
          brand: 'Bukwild',
          category: 'Shirts',
          variant: 'Black',
          price: 18.99,
          quantity: 1
        }
      ]
    }
  }
}

Customer Info

Used to send the customer info to GTM. This is not an explicit Enhanced Ecommerce event but many GTM tags want this data.

gtmEcomm.identifyCustomer(customer)
  • customer - An object that contains customer email and id, like:
{
  id: '1234'
  zip: '90210',
  email: 'abcd@test.com',

}

Pushes an object to the dataLayer that looks like:

{
  event: 'Identify Customer',
  customerId: '1234'
  customerZip: '90210',
  customerEmail: 'abcd@test.com',
}