Open navigation

Setting Up Enhanced Ecommerce through GTM and dataLayer in Shopify

Shopify Enhanced Ecommerce through GTM and dataLayer

Shopify’s unique structure introduces some distinct challenges for Enhanced Ecommerce tracking. The platform relies on an iframe-based datalayer, which can complicate data management across the site—especially when integrating third-party tools or debugging events. In this guide, we’ll show you how to set up Enhanced Ecommerce on Shopify using Google Tag Manager (GTM) and a custom datalayer. You’ll learn how to navigate Shopify’s tracking limitations and build a more flexible, extensible ecommerce analytics setup for deeper, actionable insights.

Go to Settings -> Customer events -> Click Add custom pixel

Name the pixel GTM and click Add pixel.

In the code section paste the following javascript code, which sets up a series of event tracking functions within an iframe on Shopify to capture key interactions, and send the data to the main website for enhanced tracking capabilities.

  1. Initialize the dataLayer array and the gtag function within the iframe to manage and push tracking data:
    // Define dataLayer and the gtag function in the iframe.

    window.dataLayer = window.dataLayer || [];

    function gtag(){dataLayer.push(arguments);}

  2. Create a helper function that pushes event data both to the iframe’s dataLayer and sends it to the main page using postMessage, allowing data to flow from the iframe to the primary datalayer on the main site.
    // Helper function to push to dataLayer and send to parent page

    function pushEventToDataLayer(eventData) {

     window.dataLayer.push(eventData); // Push new event data to iframe's dataLayer

     window.parent.postMessage(eventData, '*'); // Send to main page

     window.dataLayer.push({ ecommerce: null }); // Clear ecommerce object

    }

  3. Build event functions based on Shopify’s Standard Events documentation as foundation. The code aligns with Enhanced Ecommerce best practices, offering a more structured and comprehensive approach compared to Shopify's GTM tutorial. Each function captures specific interactions (such as product views, add-to-cart actions, and purchases) and prepares them for datalayer push.

    // Event: Page Viewed
    analytics.subscribe("page_viewed", (event) => {
    const eventData = {
    event: "page_view",
    url: event.context.document.location.href
    };
    pushEventToDataLayer(eventData);
    });

    // Event: Search Submitted		

    analytics.subscribe("search_submitted", (event) => {

        const eventData = {

            event: "search",

            url: event.context.document.location.href,

            search_term: event.data?.searchResult?.query,

            ecommerce: {

                item_list_id: "shopify_search",

                item_list_name: "shopify_search",

                items: event.data?.searchResult?.productVariants?.map((item) => ({

                    item_id: item.product?.id,

                    item_name: item.product?.title,

                    item_type: item.product?.type,

                    price: item.price?.amount,

                    currency: item.price?.currencyCode,

                    item_brand: item.product?.vendor,

                    item_variant: item.id,

                }))

            }

        };

        pushEventToDataLayer(eventData);

    });

    // Event: Collection Viewed		

    analytics.subscribe("collection_viewed", (event) => {

      const eventData = {

        event: "view_item_list",

        url: event.context.document.location.href,

        ecommerce: {

          item_list_id: event.data?.collection?.id,

          item_list_name: event.data?.collection?.title,

          items: event.data?.collection?.productVariants?.map((item) => ({

            item_id: item.product?.id,

            item_name: item.product?.title,

            item_type: item.product?.type,

            price: item.price?.amount,

            currency: item.price?.currencyCode,

            item_brand: item.product?.vendor,

            item_variant: item.id,

          }))

        }

      };

      pushEventToDataLayer(eventData);

    });

    // Event: Product Viewed		

    analytics.subscribe("product_viewed", (event) => {

      const eventData = {

        event: "view_item",

        url: event.context.document.location.href,

        ecommerce: {

          currency: event.data?.productVariant?.price?.currencyCode,

          value: event.data?.productVariant?.price?.amount,

          items: [

            {

              item_id: event.data?.productVariant?.product?.id,

              item_name: event.data?.productVariant?.product?.title,

              price: event.data?.productVariant?.price?.amount,

              quantity: 1

            }

          ]

        }

      };

      pushEventToDataLayer(eventData);

    });

    // Event: Product Added to Cart		

    analytics.subscribe("product_added_to_cart", (event) => {

      const eventData = {

        event: "add_to_cart",

        url: event.context.document.location.href,

        ecommerce: {

          currency: event.data?.cartLine?.cost?.totalAmount?.currencyCode,

          value: event.data?.cartLine?.cost?.totalAmount?.amount,

          items: event.data?.cartLine?.map((item) => ({

            item_id: item.merchandise?.product?.id,

            item_name: item.merchandise?.product?.title,

            item_type: item.merchandise?.product?.type,

            price: item.merchandise?.price?.amount,

            currency: item.merchandise?.price?.currencyCode,

            quantity: item.quantity,

            item_brand: item.merchandise?.product?.vendor,

            item_variant: item.merchandise?.id

          })),

        }

      };

      pushEventToDataLayer(eventData);

    });


    // Event: Cart Viewed		

    analytics.subscribe("cart_viewed", (event) => {

      const eventData = {

        event: "view_cart",

        url: event.context.document.location.href,

        ecommerce: {

          currency: event.data?.cart?.cost?.totalAmount?.currencyCode,

          value: event.data?.cart?.cost?.totalAmount?.amount,

          items: event.data?.cart?.lines?.map((item) => ({

            item_id: item.merchandise.product.id,

            item_name: item.merchandise.product.title,

            item_type: item.merchandise?.product?.type,

            price: item.merchandise?.price?.amount,

            currency: item.merchandise?.price?.currencyCode,

            quantity: item.quantity,

            item_brand: item.merchandise?.product?.vendor,

            item_variant: item.merchandise?.id

          }))

        }

      };

      pushEventToDataLayer(eventData);

    });

    // Event: Product Removed from Cart		

    analytics.subscribe("product_removed_from_cart", (event) => {

      const eventData = {

        event: "remove_from_cart",

        url: event.context.document.location.href,

        ecommerce: {

          currency: event.data?.cartLine?.merchandise?.price?.currencyCode,

          value: event.data?.cartLine?.cost?.totalAmount?.amount,

          items: [{

            item_id: event.data?.cartLine?.merchandise?.product?.id,

            item_name: event.data?.cartLine?.merchandise?.product?.title,

            item_type: event.data?.cartLine?.merchandise?.product?.type,

            price: event.data?.cartLine?.merchandise?.price?.amount,

            currency: event.data?.cartLine?.merchandise?.price?.currencyCode,

            quantity: event.data?.cartLine?.quantity,

            item_brand: event.data?.cartLine?.merchandise?.product?.vendor,

            item_variant: event.data?.cartLine?.merchandise?.id

          }]

        }

      };

      pushEventToDataLayer(eventData);

    });

    // Event: Checkout Started		

    analytics.subscribe("checkout_started", (event) => {

      const eventData = {

        event: "begin_checkout",

        url: event.context.document.location.href,

        ecommerce: {

          currency: event.data?.checkout?.currencyCode,

          value: event.data?.checkout?.subtotalPrice?.amount,

          items: event.data?.checkout?.lineItems?.map((item) => ({

            item_id: item.variant.product.id,

            item_name: item.variant.product.title,

            item_type: item.variant.product.type,

            price: item.variant.price.amount,

            currency: item.variant.price.currencyCode,

            quantity: item.quantity,

            item_brand: item.variant.product.vendor,

            item_variant: item.variant?.id

          }))

        }

      };

      pushEventToDataLayer(eventData);

    });

    // Event: Shipping Info Submitted		

    analytics.subscribe("checkout_shipping_info_submitted", (event) => {

      const eventData = {

        event: "add_shipping_info",

        url: event.context.document.location.href,

        ecommerce: {

          currency: event.data?.checkout?.currencyCode,

          value: event.data?.checkout?.subtotalPrice?.amount,

          items: event.data?.checkout?.lineItems?.map((item) => ({

            item_id: item.variant.product.id,

            item_name: item.variant.product.title,

            item_type: item.variant.product.type,

            price: item.variant.price.amount,

            currency: item.variant.price.currencyCode,

            quantity: item.quantity,

            item_brand: item.variant.product.vendor,

            item_variant: item.variant?.id

          }))

        }

      };

      pushEventToDataLayer(eventData);

    });

    // Event: Payment Info Submitted

    analytics.subscribe("payment_info_submitted", (event) => {

      const eventData = {

        event: "add_payment_info",

        url: event.context.document.location.href,

        ecommerce: {

          currency: event.data?.checkout?.currencyCode,

          value: event.data?.checkout?.subtotalPrice?.amount,

          items: event.data?.checkout?.lineItems?.map((item) => ({

            item_id: item.variant.product.id,

            item_name: item.variant.product.title,

            item_type: item.variant.product.type,

            price: item.variant.price.amount,

            currency: item.variant.price.currencyCode,

            quantity: item.quantity,

            item_brand: item.variant.product.vendor,

            item_variant: item.variant?.id

          }))

        }

      };

      pushEventToDataLayer(eventData);

    });


    // Event: Checkout Completed	

    analytics.subscribe("checkout_completed", (event) => {

      const eventData = {

        event: "purchase",

        url: event.context.document.location.href,

        ecommerce: {

          currency: event.data?.checkout?.currencyCode,

          value: event.data?.checkout?.subtotalPrice?.amount,

          transaction_id: event.data?.checkout?.order?.id,

          coupon: event.data?.checkout?.discountAllocations,

          shipping: event.data?.checkout?.shippingLine?.price?.amount,

          tax: event.data?.checkout?.totalTax?.amount,

          items: event.data?.checkout?.lineItems?.map((item) => ({

            item_id: item.variant.product.id,

            item_name: item.variant.product.title,

            item_type: item.variant.product.type,

            price: item.variant.price.amount,

            currency: item.variant.price.currencyCode,

            quantity: item.quantity,

            item_brand: item.variant.product.vendor,

            item_variant: item.variant?.id

          }))

        }

      };

      pushEventToDataLayer(eventData);

    });


Now, when you add all the above code to the Customer event, click on Connect.


After you connect, you can use the Test button to check all your events on the website in the pixel helper:

Now, go to the Online Store -> Themes -> Click on a [●●●] button on your theme and click on the Edit Code.

And now, when you verified the events are working, in your theme.liquid file put your GTM code and an event listener script that will push the data that has been sent from iframe to the website dataLayer.


    <script>

    // Listen for events from the iframe and push them to the main page's dataLayer

    window.addEventListener('message', function(event) {

      if (event.data && event.data.event) {

        window.dataLayer.push(event.data);

        window.dataLayer.push({ ecommerce: null }); // Clear ecommerce object

      }

    });

    </script>

Now the only problem left is the Checkout and Thank You page because both checkout.liquid file and Order status page additional scripts are being deprecated. On these pages you can put your GTM and dataLayer event listener code “the old way”, or we just use the iframe to send the data.


We will edit our Begin Checkout event from GTM Customer Event

// Event: Checkout Started

analytics.subscribe("checkout_started", (event) => {

  const eventData = {

    event: "begin_checkout",

    url: event.context.document.location.href,

    ecommerce: {

      currency: event.data?.checkout?.currencyCode,

      value: event.data?.checkout?.subtotalPrice?.amount,

      items: event.data?.checkout?.lineItems?.map((item) => ({

        item_id: item.variant.product.id,

        item_name: item.variant.product.title,

        price: item.variant.price.amount,

        quantity: item.quantity

      }))

    }

  };

  pushEventToDataLayer(eventData);

);

  // Load GTM specifically on checkout start

  (function(w,d,s,l,i){

    w[l]=w[l]||[];

    w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'});

    var f=d.getElementsByTagName(s)[0],

        j=d.createElement(s), dl=l!='dataLayer'?'&l='+l:'';

    j.async=true; j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;

    f.parentNode.insertBefore(j,f);

  })(window,document,'script','dataLayer','GTM-KPRHW532'); // Use your GTM ID

});

And we will also update Checkout Completed event, because that happens on thank you page to also load your GTM code:


// Event: Checkout Completed

analytics.subscribe("checkout_completed", (event) => {

  const eventData = {

    event: "purchase",

    url: event.context.document.location.href,

    ecommerce: {

      currency: event.data?.checkout?.currencyCode,

      value: event.data?.checkout?.subtotalPrice?.amount,

      transaction_id: event.data?.checkout?.order?.id,

      coupon: event.data?.checkout?.discountAllocations,

      shipping: event.data?.checkout?.shippingLine?.price?.amount,

      tax: event.data?.checkout?.totalTax?.amount,

      items: event.data?.checkout?.lineItems?.map((item) => ({

        item_id: item.variant.product.id,

        item_name: item.variant.product.title,

        price: item.variant.price.amount,

        quantity: item.quantity

      }))

    }

  };

  pushEventToDataLayer(eventData);


  // Load GTM and Consent Mode specifically on checkout completed

  (function(w,d,s,l,i){

    w[l]=w[l]||[];

    w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'});

    var f=d.getElementsByTagName(s)[0],

        j=d.createElement(s), dl=l!='dataLayer'?'&l='+l:'';

    j.async=true; j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;

    f.parentNode.insertBefore(j,f);

  })(window,document,'script','dataLayer','GTM-KPRHW532'); // Use your GTM ID

});

You are now all done with the code, now the last thing that needs to be done is to set up your GTM. Create new Trigger, name it EE Shopify Events, select trigger type Custom Event. In the Event name put the following Regex match, and hit save:

^(view_search_results|page_view|view_item_list|view_item|select_item|add_to_cart|view_cart|remove_from_cart|begin_checkout|add_shipping_info|add_payment_info|purchase|)$


Go to Tags -> Create New Tag -> In the tag configuration select Google Analytics: GA4 Event


Name it GA4 Shopify events and for Firing Trigger select the EE Shopify Events you just recently created. In the Measurement ID put your GA4 Tracking ID. In the Event Name set the {{Event}}. Under more settings, expand Ecommerce and Select Send Ecommerce data and Data source Data Layer.


Did you find it helpful? Yes No

Send feedback
Sorry we couldn't be helpful. Help us improve this article with your feedback.