Tracking Shopify e-commerce with GTM offers great flexibility, but to do it effectively, you need a solid Shopify DataLayer. Finding a fully-featured DataLayer that covers all types of e-commerce events, provides complete event parameters and user data, and handles any data discrepancies can be challenging. To address this, I’ve developed a powerful and flexible Shopify DataLayer that tracks all required events seamlessly.
What You Will Learn
Events List You Can Track
| No | Event Name | Description |
|---|---|---|
| 1 | view_item | When view a product. This Shopify datalayer works for both product page view and view product on quick view |
| 2 | view_item_list | When product category page visited. Also customized solution available for view item list on product recommendations |
| 3 | select_item | When product select from list or change product variant |
| 4 | add_to_cart | When a product is added to cart or increment quantity of a product from cart. The Shopify DataLayer works Quick View, Sticky Cart, Direct Checkout, Add to Cart form Single Product page, add to cart from product category page, etc |
| 5 | remove_from_cart | When a item is removed from cart. The Shopify DataLayer works for Mini Cart and Dropdown Cart, Cart Drawer, Cart Page |
| 6 | add_to_wishlist | When custom add a product to Wishlist basket |
| 7 | view_cart | When cart is viewed. This Shopify dataLayer works for for Mini Cart and Dropdown Cart, Cart Drawer, Cart Page |
| 8 | begin_checkout | When click begin checkout button to go to checkout page |
| 9 | add_payment_info | When payment information is given on checkout page |
| 10 | add_shopping_info | When shipping information is given on checkout page |
| 11 | purchase | When purchase successful |
| newsletter_signup | When signup for a newsletter form from Shopify Store | |
| 12 | contact_form_submit | When contact form is submitted from Shopify Store |
| phone_number_click | When phone number is clicked from Shopify Store | |
| 13 | email_click | When email is click from Shopify Store |
| 14 | search (Ajax) | search_term, items[item_id, variant_id, sku, product_id, item_name, index, brand, item_category, price, quantity] |
| 15 | login | When customer login |
| 16 | sign_up | When customer signup |
Ecommerc: transaction_id, currency, value, coupon, shipping, tax, items array, item_list_id, item_list_name,
Form: form_id, email, phone number, first name, last name, other user data
Customer’s Data: First Name, Last Name, Email, Hashed Email, Phone Number, Hashed Phone Number, Address
How to Setup Shopify DataLayer?
Follow the following step by step guide to connect Shopify DataLayer with your Shopify Store
Step 1: Adding GTM Tracking Code
Access your Shopify Store Dashboard. Navigate to Online Store > Themes > Edit code (3 dots on the right of the active theme) and find the theme.liquid file. Copy google Tag manager tacking code and paste the code right after the <head> tag in the theme.liquid file.

Step 2: Adding DataLayer Code
- Inside the
snippetsfolder, create a new file namedultimate-datalayer.liquid - Copy code from the
ultimate-datalayer.liquidshown at the bellow and paste it into the newly createdultimate-datalayer.liquidfile.

ultimate-datalayer.liquid
<script>
/**
* Author: Md Hasanuzzamna
* Email: info@leomeasure.com
* Linkedin: https://linkedin.com/in/md-h
* Version: 3.6.1
* Last Update: 27 May 2025
*/
(function() {
class Ultimate_Shopify_DataLayer {
constructor() {
window.dataLayer = window.dataLayer || [];
// use a prefix of events name
this.eventPrefix = '';
//Keep the value false to get non-formatted product ID
this.formattedItemId = true;
// data schema
this.dataSchema = {
ecommerce: {
show: true
},
dynamicRemarketing: {
show: false,
business_vertical: 'retail'
}
}
// add to wishlist selectors
this.addToWishListSelectors = {
'addWishListIcon': '',
'gridItemSelector': '',
'productLinkSelector': 'a[href*="/products/"]'
}
// quick view selectors
this.quickViewSelector = {
'quickViewElement': '',
'gridItemSelector': '',
'productLinkSelector': 'a[href*="/products/"]'
}
// mini cart button selector
this.miniCartButton = [
'a[href="/cart"]',
];
this.miniCartAppersOn = 'click';
// begin checkout buttons/links selectors
this.beginCheckoutButtons = [
'input[name="checkout"]',
'button[name="checkout"]',
'a[href="/checkout"]',
'.additional-checkout-buttons',
];
// direct checkout button selector
this.shopifyDirectCheckoutButton = [
'.shopify-payment-button'
]
//Keep the value true if Add to Cart redirects to the cart page
this.isAddToCartRedirect = false;
// keep the value false if cart items increment/decrement/remove refresh page
this.isAjaxCartIncrementDecrement = true;
// Caution: Do not modify anything below this line, as it may result in it not functioning correctly.
this.cart = {{ cart | json }}
this.countryCode = "{{ shop.address.country_code }}";
this.storeURL = "{{ shop.secure_url }}";
localStorage.setItem('shopCountryCode', this.countryCode);
this.collectData();
this.itemsList = [];
}
updateCart() {
fetch("/cart.js")
.then((response) => response.json())
.then((data) => {
this.cart = data;
});
}
debounce(delay) {
let timeoutId;
return function(func) {
const context = this;
const args = arguments;
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
func.apply(context, args);
}, delay);
};
}
eventConsole(eventName, eventData) {
const css1 = 'background: red; color: #fff; font-size: normal; border-radius: 3px 0 0 3px; padding: 3px 4px;';
const css2 = 'background-color: blue; color: #fff; font-size: normal; border-radius: 0 3px 3px 0; padding: 3px 4px;';
console.log('%cGTM DataLayer Event:%c' + eventName, css1, css2, eventData);
}
collectData() {
this.customerData();
this.ajaxRequestData();
this.searchPageData();
this.miniCartData();
this.beginCheckoutData();
{% if template contains 'cart' %}
this.viewCartPageData();
{% endif %}
{% if template contains 'product' %}
this.productSinglePage();
{% endif %}
{% if template contains 'collection' %}
this.collectionsPageData();
{% endif %}
this.addToWishListData();
this.quickViewData();
this.selectItemData();
this.formData();
this.phoneClickData();
this.emailClickData();
this.loginRegisterData();
}
//logged-in customer data
customerData() {
const currentUser = {};
{% if customer %}
currentUser.id = {{ customer.id }};
currentUser.first_name = "{{ customer.first_name }}";
currentUser.last_name = "{{ customer.last_name }}";
currentUser.full_name = "{{ customer.name }}";
currentUser.email = "{{ customer.email }}";
currentUser.phone = "{{ customer.default_address.phone }}";
{% if customer.default_address %}
currentUser.address = {
address_summary: "{{ customer.default_address.summary }}",
address1: "{{ customer.default_address.address1 }}",
address2: "{{ customer.default_address.address2 }}",
city: "{{ customer.default_address.city }}",
street: "{{ customer.default_address.street }}",
zip: "{{ customer.default_address.zip }}",
company: "{{ customer.default_address.company }}",
country: "{{ customer.default_address.country.name }}",
countryCode: "{{ customer.default_address.country_code }}",
province: "{{ customer.default_address.province }}"
};
{% endif %}
{% endif %}
if (currentUser.email) {
currentUser.hash_email = "{{ customer.email | sha256 }}"
}
if (currentUser.phone) {
currentUser.hash_phone = "{{ customer.phone | sha256 }}"
}
window.dataLayer = window.dataLayer || [];
dataLayer.push({
customer: currentUser
});
}
// add_to_cart, remove_from_cart, search
ajaxRequestData() {
const self = this;
// handle non-ajax add to cart
if(this.isAddToCartRedirect) {
document.addEventListener('submit', function(event) {
const addToCartForm = event.target.closest('form[action="/cart/add"]');
if(addToCartForm) {
event.preventDefault();
const formData = new FormData(addToCartForm);
fetch(window.Shopify.routes.root + 'cart/add.js', {
method: 'POST',
body: formData
})
.then(response => {
window.location.href = "{{ routes.cart_url }}";
})
.catch((error) => {
console.error('Error:', error);
});
}
});
}
// fetch
let originalFetch = window.fetch;
let debounce = this.debounce(800);
window.fetch = function () {
return originalFetch.apply(this, arguments).then((response) => {
if (response.ok) {
let cloneResponse = response.clone();
let requestURL = arguments[0]['url'] || arguments[0];
if(typeof requestURL === 'string' && /.*\/search\/?.*\?.*q=.+/.test(requestURL) && !requestURL.includes('&requestFrom=uldt')) {
const queryString = requestURL.split('?')[1];
const urlParams = new URLSearchParams(queryString);
const search_term = urlParams.get("q");
debounce(function() {
fetch(`${self.storeURL}/search/suggest.json?q=${search_term}&resources[type]=product&requestFrom=uldt`)
.then(res => res.json())
.then(function(data) {
const products = data.resources.results.products;
if(products.length) {
const fetchRequests = products.map(product =>
fetch(`${self.storeURL}/${product.url.split('?')[0]}.js`)
.then(response => response.json())
.catch(error => console.error('Error fetching:', error))
);
Promise.all(fetchRequests)
.then(products => {
const items = products.map((product) => {
return {
product_id: product.id,
product_title: product.title,
variant_id: product.variants[0].id,
variant_title: product.variants[0].title,
vendor: product.vendor,
total_discount: 0,
final_price: product.price_min,
product_type: product.type,
quantity: 1
}
});
self.ecommerceDataLayer('search', {search_term, items});
})
}else {
self.ecommerceDataLayer('search', {search_term, items: []});
}
});
});
}
else if (typeof requestURL === 'string' && requestURL.includes("/cart/add")) {
cloneResponse.text().then((text) => {
let data = JSON.parse(text);
if(data.items && Array.isArray(data.items)) {
data.items.forEach(function(item) {
self.ecommerceDataLayer('add_to_cart', {items: [item]});
})
} else {
self.ecommerceDataLayer('add_to_cart', {items: [data]});
}
self.updateCart();
});
}else if(typeof requestURL === 'string' && (requestURL.includes("/cart/change") || requestURL.includes("/cart/update"))) {
cloneResponse.text().then((text) => {
let newCart = JSON.parse(text);
let newCartItems = newCart.items;
let oldCartItems = self.cart.items;
for(let i = 0; i < oldCartItems.length; i++) {
let item = oldCartItems[i];
let newItem = newCartItems.find(newItems => newItems.id === item.id);
if(newItem) {
if(newItem.quantity > item.quantity) {
// cart item increment
let quantity = (newItem.quantity - item.quantity);
let updatedItem = {...item, quantity}
self.ecommerceDataLayer('add_to_cart', {items: [updatedItem]});
self.updateCart();
}else if(newItem.quantity < item.quantity) {
// cart item decrement
let quantity = (item.quantity - newItem.quantity);
let updatedItem = {...item, quantity}
self.ecommerceDataLayer('remove_from_cart', {items: [updatedItem]});
self.updateCart();
}
}else {
self.ecommerceDataLayer('remove_from_cart', {items: [item]});
self.updateCart();
}
}
});
}
}
return response;
});
}
// end fetch
//xhr
var origXMLHttpRequest = XMLHttpRequest;
XMLHttpRequest = function() {
var requestURL;
var xhr = new origXMLHttpRequest();
var origOpen = xhr.open;
var origSend = xhr.send;
// Override the `open` function.
xhr.open = function(method, url) {
requestURL = url;
return origOpen.apply(this, arguments);
};
xhr.send = function() {
// Only proceed if the request URL matches what we're looking for.
if (typeof requestURL === 'string' && (requestURL.includes("/cart/add") || requestURL.includes("/cart/change") || /.*\/search\/?.*\?.*q=.+/.test(requestURL))) {
xhr.addEventListener('load', function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 400) {
if(typeof requestURL === 'string' && /.*\/search\/?.*\?.*q=.+/.test(requestURL) && !requestURL.includes('&requestFrom=uldt')) {
const queryString = requestURL.split('?')[1];
const urlParams = new URLSearchParams(queryString);
const search_term = urlParams.get("q");
debounce(function() {
fetch(`${self.storeURL}/search/suggest.json?q=${search_term}&resources[type]=product&requestFrom=uldt`)
.then(res => res.json())
.then(function(data) {
const products = data.resources.results.products;
if(products.length) {
const fetchRequests = products.map(product =>
fetch(`${self.storeURL}/${product.url.split('?')[0]}.js`)
.then(response => response.json())
.catch(error => console.error('Error fetching:', error))
);
Promise.all(fetchRequests)
.then(products => {
const items = products.map((product) => {
return {
product_id: product.id,
product_title: product.title,
variant_id: product.variants[0].id,
variant_title: product.variants[0].title,
vendor: product.vendor,
total_discount: 0,
final_price: product.price_min,
product_type: product.type,
quantity: 1
}
});
self.ecommerceDataLayer('search', {search_term, items});
})
}else {
self.ecommerceDataLayer('search', {search_term, items: []});
}
});
});
}
else if(typeof requestURL === 'string' && requestURL.includes("/cart/add")) {
const data = JSON.parse(xhr.responseText);
if(data.items && Array.isArray(data.items)) {
data.items.forEach(function(item) {
self.ecommerceDataLayer('add_to_cart', {items: [item]});
})
} else {
self.ecommerceDataLayer('add_to_cart', {items: [data]});
}
self.updateCart();
}else if(typeof requestURL === 'string' && requestURL.includes("/cart/change")) {
const newCart = JSON.parse(xhr.responseText);
const newCartItems = newCart.items;
let oldCartItems = self.cart.items;
for(let i = 0; i < oldCartItems.length; i++) {
let item = oldCartItems[i];
let newItem = newCartItems.find(newItems => newItems.id === item.id);
if(newItem) {
if(newItem.quantity > item.quantity) {
// cart item increment
let quantity = (newItem.quantity - item.quantity);
let updatedItem = {...item, quantity}
self.ecommerceDataLayer('add_to_cart', {items: [updatedItem]});
self.updateCart();
}else if(newItem.quantity < item.quantity) {
// cart item decrement
let quantity = (item.quantity - newItem.quantity);
let updatedItem = {...item, quantity}
self.ecommerceDataLayer('remove_from_cart', {items: [updatedItem]});
self.updateCart();
}
}else {
self.ecommerceDataLayer('remove_from_cart', {items: [item]});
self.updateCart();
}
}
}
}
}
});
}
return origSend.apply(this, arguments);
};
return xhr;
};
//end xhr
}
// search event from search page
searchPageData() {
const self = this;
let pageUrl = window.location.href;
if(/.+\/search\?.*\&?q=.+/.test(pageUrl)) {
const queryString = pageUrl.split('?')[1];
const urlParams = new URLSearchParams(queryString);
const search_term = urlParams.get("q");
fetch(`{{ shop.secure_url }}/search/suggest.json?q=${search_term}&resources[type]=product&requestFrom=uldt`)
.then(res => res.json())
.then(function(data) {
const products = data.resources.results.products;
if(products.length) {
const fetchRequests = products.map(product =>
fetch(`${self.storeURL}/${product.url.split('?')[0]}.js`)
.then(response => response.json())
.catch(error => console.error('Error fetching:', error))
);
Promise.all(fetchRequests)
.then(products => {
const items = products.map((product) => {
return {
product_id: product.id,
product_title: product.title,
variant_id: product.variants[0].id,
variant_title: product.variants[0].title,
vendor: product.vendor,
total_discount: 0,
final_price: product.price_min,
product_type: product.type,
quantity: 1
}
});
self.ecommerceDataLayer('search', {search_term, items});
});
}else {
self.ecommerceDataLayer('search', {search_term, items: []});
}
});
}
}
// view_cart
miniCartData() {
if(this.miniCartButton.length) {
let self = this;
if(this.miniCartAppersOn === 'hover') {
this.miniCartAppersOn = 'mouseenter';
}
this.miniCartButton.forEach((selector) => {
let miniCartButtons = document.querySelectorAll(selector);
miniCartButtons.forEach((miniCartButton) => {
miniCartButton.addEventListener(self.miniCartAppersOn, () => {
self.ecommerceDataLayer('view_cart', self.cart);
});
})
});
}
}
// begin_checkout
beginCheckoutData() {
let self = this;
document.addEventListener('pointerdown', (event) => {
let targetElement = event.target.closest(self.beginCheckoutButtons.join(', '));
if(targetElement) {
self.ecommerceDataLayer('begin_checkout', self.cart);
}
});
}
// view_cart, add_to_cart, remove_from_cart
viewCartPageData() {
this.ecommerceDataLayer('view_cart', this.cart);
//if cart quantity chagne reload page
if(!this.isAjaxCartIncrementDecrement) {
const self = this;
document.addEventListener('pointerdown', (event) => {
const target = event.target.closest('a[href*="/cart/change?"]');
if(target) {
const linkUrl = target.getAttribute('href');
const queryString = linkUrl.split("?")[1];
const urlParams = new URLSearchParams(queryString);
const newQuantity = urlParams.get("quantity");
const line = urlParams.get("line");
const cart_id = urlParams.get("id");
if(newQuantity && (line || cart_id)) {
let item = line ? {...self.cart.items[line - 1]} : self.cart.items.find(item => item.key === cart_id);
let event = 'add_to_cart';
if(newQuantity < item.quantity) {
event = 'remove_from_cart';
}
let quantity = Math.abs(newQuantity - item.quantity);
item['quantity'] = quantity;
self.ecommerceDataLayer(event, {items: [item]});
}
}
});
}
}
productSinglePage() {
{% if template contains 'product' %}
const item = {
product_id: {{ product.id | json }},
variant_id: {{ product.selected_or_first_available_variant.id }},
product_title: {{ product.title | json }},
line_level_total_discount: 0,
vendor: {{ product.vendor | json }},
sku: {{ product.selected_or_first_available_variant.sku | json }},
product_type: {{ product.type | json }},
item_list_id: {{ product.collections[0].id | json }},
item_list_name: {{ product.collections[0].title | json }},
{% if product.selected_or_first_available_variant.title != "Default Title" %}
variant_title: {{ product.selected_or_first_available_variant.title | json }},
{% endif %}
final_price: {{ product.selected_or_first_available_variant.price }},
quantity: 1
};
const variants = {{ product.variants | json }}
this.ecommerceDataLayer('view_item', {items: [item]});
if(this.shopifyDirectCheckoutButton.length) {
let self = this;
document.addEventListener('pointerdown', (event) => {
let target = event.target;
let checkoutButton = event.target.closest(this.shopifyDirectCheckoutButton.join(', '));
if(checkoutButton && (variants || self.quickViewVariants)) {
let checkoutForm = checkoutButton.closest('form[action*="/cart/add"]');
if(checkoutForm) {
let variant_id = null;
let varientInput = checkoutForm.querySelector('input[name="id"]');
let varientIdFromURL = new URLSearchParams(window.location.search).get('variant');
let firstVarientId = item.variant_id;
if(varientInput) {
variant_id = parseInt(varientInput.value);
}else if(varientIdFromURL) {
variant_id = varientIdFromURL;
}else if(firstVarientId) {
variant_id = firstVarientId;
}
if(variant_id) {
variant_id = parseInt(variant_id);
let quantity = 1;
let quantitySelector = checkoutForm.getAttribute('id');
if(quantitySelector) {
let quentityInput = document.querySelector('input[name="quantity"][form="'+quantitySelector+'"]');
if(quentityInput) {
quantity = +quentityInput.value;
}
}
if(variant_id) {
let variant = variants.find(item => item.id === +variant_id);
if(variant && item) {
variant_id
item['variant_id'] = variant_id;
item['variant_title'] = variant.title;
item['final_price'] = variant.price;
item['quantity'] = quantity;
self.ecommerceDataLayer('add_to_cart', {items: [item]});
self.ecommerceDataLayer('begin_checkout', {items: [item]});
}else if(self.quickViewedItem) {
let variant = self.quickViewVariants.find(item => item.id === +variant_id);
if(variant) {
self.quickViewedItem['variant_id'] = variant_id;
self.quickViewedItem['variant_title'] = variant.title;
self.quickViewedItem['final_price'] = parseFloat(variant.price) * 100;
self.quickViewedItem['quantity'] = quantity;
self.ecommerceDataLayer('add_to_cart', {items: [self.quickViewedItem]});
self.ecommerceDataLayer('begin_checkout', {items: [self.quickViewedItem]});
}
}
}
}
}
}
});
}
{% endif %}
}
collectionsPageData() {
var ecommerce = {
'items': [
{% for product in collection.products %}
{
'product_id': {{ product.id | json }},
'variant_id': {{ product.selected_or_first_available_variant.id | json }},
'vendor': {{ product.vendor | json }},
'sku': {{ product.selected_or_first_available_variant.sku | json }},
'total_discount': 0,
'variant_title': {{ product.selected_or_first_available_variant.title | json }},
'product_title': {{ product.title | json }},
'final_price': Number({{ product.price }}),
'product_type': {{ product.type | json }},
'item_list_id': {{ collection.id | json }},
'item_list_name': {{ collection.title | json }},
'url': {{product.url | json}},
'quantity': 1
},
{% endfor %}
]
};
this.itemsList = ecommerce.items;
ecommerce['item_list_id'] = {{ collection.id | json }}
ecommerce['item_list_name'] = {{ collection.title | json }}
this.ecommerceDataLayer('view_item_list', ecommerce);
}
// add to wishlist
addToWishListData() {
if(this.addToWishListSelectors && this.addToWishListSelectors.addWishListIcon) {
const self = this;
document.addEventListener('pointerdown', (event) => {
let target = event.target;
if(target.closest(self.addToWishListSelectors.addWishListIcon)) {
let pageULR = window.location.href.replace(/\?.+/, '');
let requestURL = undefined;
if(/\/products\/[^/]+$/.test(pageULR)) {
requestURL = pageULR;
} else if(self.addToWishListSelectors.gridItemSelector && self.addToWishListSelectors.productLinkSelector) {
let itemElement = target.closest(self.addToWishListSelectors.gridItemSelector);
if(itemElement) {
let linkElement = itemElement.querySelector(self.addToWishListSelectors.productLinkSelector);
if(linkElement) {
let link = linkElement.getAttribute('href').replace(/\?.+/g, '');
if(link && /\/products\/[^/]+$/.test(link)) {
requestURL = link;
}
}
}
}
if(requestURL) {
fetch(requestURL + '.json')
.then(res => res.json())
.then(result => {
let data = result.product;
if(data) {
let dataLayerData = {
product_id: data.id,
variant_id: data.variants[0].id,
product_title: data.title,
quantity: 1,
final_price: parseFloat(data.variants[0].price) * 100,
total_discount: 0,
product_type: data.product_type,
vendor: data.vendor,
variant_title: (data.variants[0].title !== 'Default Title') ? data.variants[0].title : undefined,
sku: data.variants[0].sku,
}
self.ecommerceDataLayer('add_to_wishlist', {items: [dataLayerData]});
}
});
}
}
});
}
}
quickViewData() {
if(this.quickViewSelector.quickViewElement && this.quickViewSelector.gridItemSelector && this.quickViewSelector.productLinkSelector) {
const self = this;
document.addEventListener('pointerdown', (event) => {
let target = event.target;
if(target.closest(self.quickViewSelector.quickViewElement)) {
let requestURL = undefined;
let itemElement = target.closest(this.quickViewSelector.gridItemSelector );
if(itemElement) {
let linkElement = itemElement.querySelector(self.quickViewSelector.productLinkSelector);
if(linkElement) {
let link = linkElement.getAttribute('href').replace(/\?.+/g, '');
if(link && /\/products\/[^/]+$/.test(link)) {
requestURL = link;
}
}
}
if(requestURL) {
fetch(requestURL + '.json')
.then(res => res.json())
.then(result => {
let data = result.product;
if(data) {
let dataLayerData = {
product_id: data.id,
variant_id: data.variants[0].id,
product_title: data.title,
quantity: 1,
final_price: parseFloat(data.variants[0].price) * 100,
total_discount: 0,
product_type: data.product_type,
vendor: data.vendor,
variant_title: (data.variants[0].title !== 'Default Title') ? data.variants[0].title : undefined,
sku: data.variants[0].sku,
}
self.ecommerceDataLayer('view_item', {items: [dataLayerData]});
self.quickViewVariants = data.variants;
self.quickViewedItem = dataLayerData;
}
});
}
}
});
{% unless template contains 'product' %}
if(this.shopifyDirectCheckoutButton.length) {
let self = this;
document.addEventListener('pointerdown', (event) => {
let target = event.target;
let checkoutButton = event.target.closest(this.shopifyDirectCheckoutButton.join(', '));
if(self.quickViewVariants && self.quickViewedItem && self.quickViewVariants.length && checkoutButton) {
let checkoutForm = checkoutButton.closest('form[action*="/cart/add"]');
if(checkoutForm) {
let quantity = 1;
let varientInput = checkoutForm.querySelector('input[name="id"]');
let quantitySelector = checkoutForm.getAttribute('id');
if(quantitySelector) {
let quentityInput = document.querySelector('input[name="quantity"][form="'+quantitySelector+'"]');
if(quentityInput) {
quantity = +quentityInput.value;
}
}
if(varientInput) {
let variant_id = parseInt(varientInput.value);
if(variant_id) {
const variant = self.quickViewVariants.find(item => item.id === +variant_id);
if(variant && self.quickViewedItem) {
self.quickViewedItem['variant_id'] = variant_id;
self.quickViewedItem['variant_title'] = variant.title;
self.quickViewedItem['final_price'] = parseFloat(variant.price) * 100;
self.quickViewedItem['quantity'] = quantity;
self.ecommerceDataLayer('add_to_cart', {items: [self.quickViewedItem]});
self.ecommerceDataLayer('begin_checkout', {items: [self.quickViewedItem]});
}
}
}
}
}
});
}
{% endunless %}
}
}
// select_item events
selectItemData() {
const self = this;
const items = this.itemsList;
{% if template contains 'collection' %}
document.addEventListener('pointerdown', function(event) {
const productLink = event.target.closest('a[href*="/products/"]');
if(productLink) {
const linkUrl = productLink.getAttribute('href');
const matchProduct = (item) => {
var itemSlug = (item.url.split('/products/')[1]).split('#')[0].split('?')[0].trim();
var linkUrlItemSlug = (linkUrl.split('/products/')[1]).split('#')[0].split('?')[0].trim();
return itemSlug === linkUrlItemSlug;
}
const item = items.find(matchProduct);
const index = items.findIndex(matchProduct);
if(item) {
self.ecommerceDataLayer('select_item', {items: [{...item, index: index}]});
}
}
});
{% endif %}
// select item on varient change
document.addEventListener('variant:change', function(event) {
const product_id = event.detail.product.id;
const variant_id = event.detail.variant.id;
const vendor = event.detail.product.vendor;
const variant_title = event.detail.variant.public_title;
const product_title = event.detail.product.title;
const final_price = event.detail.variant.price;
const product_type = event.detail.product.type;
const item = {
product_id: product_id,
product_title: product_title,
variant_id: variant_id,
variant_title: variant_title,
vendor: vendor,
final_price: final_price,
product_type: product_type,
quantity: 1
}
self.ecommerceDataLayer('select_item', {items: [item]});
});
}
// all ecommerce events
ecommerceDataLayer(event, data) {
const self = this;
dataLayer.push({ 'ecommerce': null });
const dataLayerData = {
"event": this.eventPrefix + event,
'ecommerce': {
'currency': this.cart.currency,
'items': data.items.map((item, index) => {
const dataLayerItem = {
'index': index,
'item_id': this.formattedItemId ? `shopify_${this.countryCode}_${item.product_id}_${item.variant_id}` : item.product_id.toString(),
'product_id': item.product_id.toString(),
'variant_id': item.variant_id.toString(),
'item_name': item.product_title,
'quantity': item.quantity,
'price': +((item.final_price / 100).toFixed(2)),
'discount': item.total_discount ? +((item.total_discount / 100).toFixed(2)) : 0
}
if(item.product_type) {
dataLayerItem['item_category'] = item.product_type;
}
if(item.vendor) {
dataLayerItem['item_brand'] = item.vendor;
}
if(item.variant_title && item.variant_title !== 'Default Title') {
dataLayerItem['item_variant'] = item.variant_title;
}
if(item.sku) {
dataLayerItem['sku'] = item.sku;
}
if(item.item_list_name) {
dataLayerItem['item_list_name'] = item.item_list_name;
}
if(item.item_list_id) {
dataLayerItem['item_list_id'] = item.item_list_id.toString()
}
return dataLayerItem;
})
}
}
if(data.total_price !== undefined) {
dataLayerData['ecommerce']['value'] = +((data.total_price / 100).toFixed(2));
} else {
dataLayerData['ecommerce']['value'] = +(dataLayerData['ecommerce']['items'].reduce((total, item) => total + (item.price * item.quantity), 0)).toFixed(2);
}
if(data.item_list_id) {
dataLayerData['ecommerce']['item_list_id'] = data.item_list_id;
}
if(data.item_list_name) {
dataLayerData['ecommerce']['item_list_name'] = data.item_list_name;
}
if(data.search_term) {
dataLayerData['search_term'] = data.search_term;
}
if(self.dataSchema.dynamicRemarketing && self.dataSchema.dynamicRemarketing.show) {
dataLayer.push({ 'dynamicRemarketing': null });
dataLayerData['dynamicRemarketing'] = {
value: dataLayerData.ecommerce.value,
items: dataLayerData.ecommerce.items.map(item => ({id: item.item_id, google_business_vertical: self.dataSchema.dynamicRemarketing.business_vertical}))
}
}
if(!self.dataSchema.ecommerce || !self.dataSchema.ecommerce.show) {
delete dataLayerData['ecommerce'];
}
dataLayer.push(dataLayerData);
self.eventConsole(self.eventPrefix + event, dataLayerData);
}
// contact form submit & newsletters signup
formData() {
const self = this;
document.addEventListener('submit', function(event) {
let targetForm = event.target.closest('form[action^="/contact"]');
if(targetForm) {
const formData = {
form_location: window.location.href,
form_id: targetForm.getAttribute('id'),
form_classes: targetForm.getAttribute('class')
};
let formType = targetForm.querySelector('input[name="form_type"]');
let inputs = targetForm.querySelectorAll("input:not([type=hidden]):not([type=submit]), textarea, select");
inputs.forEach(function(input) {
var inputName = input.name;
var inputValue = input.value;
if (inputName && inputValue) {
var matches = inputName.match(/\[(.*?)\]/);
if (matches && matches.length > 1) {
var fieldName = matches[1];
formData[fieldName] = input.value;
}
}
});
if(formType && formType.value === 'customer') {
dataLayer.push({ event: self.eventPrefix + 'newsletter_signup', ...formData});
self.eventConsole(self.eventPrefix + 'newsletter_signup', { event: self.eventPrefix + 'newsletter_signup', ...formData});
} else if(formType && formType.value === 'contact') {
dataLayer.push({ event: self.eventPrefix + 'contact_form_submit', ...formData});
self.eventConsole(self.eventPrefix + 'contact_form_submit', { event: self.eventPrefix + 'contact_form_submit', ...formData});
}
}
});
}
// phone_number_click event
phoneClickData() {
const self = this;
document.addEventListener('click', function(event) {
let target = event.target.closest('a[href^="tel:"]');
if(target) {
let phone_number = target.getAttribute('href').replace('tel:', '');
let eventData = {
event: self.eventPrefix + 'phone_number_click',
page_location: window.location.href,
link_classes: target.getAttribute('class'),
link_id: target.getAttribute('id'),
phone_number
}
dataLayer.push(eventData);
self.eventConsole(self.eventPrefix + 'phone_number_click', eventData);
}
});
}
// email_click event
emailClickData() {
const self = this;
document.addEventListener('click', function(event) {
let target = event.target.closest('a[href^="mailto:"]');
if(target) {
let email_address = target.getAttribute('href').replace('mailto:', '');
let eventData = {
event: self.eventPrefix + 'email_click',
page_location: window.location.href,
link_classes: target.getAttribute('class'),
link_id: target.getAttribute('id'),
email_address
}
dataLayer.push(eventData);
self.eventConsole(self.eventPrefix + 'email_click', eventData);
}
});
}
//login register
loginRegisterData() {
const self = this;
let isTrackedLogin = false;
let isTrackedRegister = false;
if(window.location.href.includes('/account/login')) {
document.addEventListener('submit', function(e) {
const loginForm = e.target.closest('[action="/account/login"]');
if(loginForm && !isTrackedLogin) {
const eventData = {
event: self.eventPrefix + 'login'
}
isTrackedLogin = true;
dataLayer.push(eventData);
self.eventConsole(self.eventPrefix + 'login', eventData);
}
});
}
if(window.location.href.includes('/account/register')) {
document.addEventListener('submit', function(e) {
const registerForm = e.target.closest('[action="/account"]');
if(registerForm && !isTrackedRegister) {
const eventData = {
event: self.eventPrefix + 'sign_up'
}
isTrackedRegister = true;
dataLayer.push(eventData);
self.eventConsole(self.eventPrefix + 'sign_up', eventData);
}
});
}
}
}
// end Ultimate_Shopify_DataLayer
document.addEventListener('DOMContentLoaded', function() {
try{
new Ultimate_Shopify_DataLayer();
}catch(error) {
console.log(error);
}
});
})();
</script>
Step 3: DataLayer in Theme File
In the theme.liquid file, after your GTM tracking code, include the ultimate-datalayer.liquid file by adding {% render 'ultimate-datalayer' %}

Step 4: Add DataLayer Code for Checkout
- From your Shopify Admin Dashboard, navigate to Settings → Customer events. In the top-right corner, click Add custom pixel to create a new custom pixel. Next, enter a title for the pixel and create it.
- Remove all commented code from the code editor. Then, copy the entire code from bellow “checkout-webpixel.js” and paste it into the code field of your new custom pixel.
- At the very top of the code, replace the sample GTM Tracking ID GTM-00000000 with your actual Google Tag Manager ID. If you’re using server-side tagging with a custom domain, update the Tag Manager URL to match your website’s subdomain.
- In the Customer privacy settings section – For the Permission option, select Not required – The pixel will always run and for the Data sale option, choose Data collected does not qualify as data sale.
- Finally, click connect button in the top right corner to connect custom pixel.
checkout-webpixel.js
const event_prefix = '';
const formattedItemId = true;
const gclidWithPageLocation = false;
const GTM_container_url = 'https://www.googletagmanager.com';
const GTM_container_id = 'GTM-00000000';
let storeCountryCode = window.localStorage.getItem('shopCountryCode');
storeCountryCode = storeCountryCode || 'US';
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
//checkout pages event
if(/.+\/checkouts?\/.*/.test(window.location.href)) {
// tag manager
(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 = GTM_container_url + '/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', GTM_container_id);
analytics.subscribe('page_viewed', (event) => {
const eventData = {
event: event_prefix + 'page_view',
page_location: getPageLocation(event),
}
window.dataLayer.push(eventData);
eventLog('page_view', eventData);
});
// end tag manager
// DataLayer Events
analytics.subscribe('payment_info_submitted', (event) => ecommerceDataLayer('add_payment_info', event));
analytics.subscribe('checkout_shipping_info_submitted', (event) => ecommerceDataLayer('add_shipping_info', event));
analytics.subscribe('checkout_completed', (event) => ecommerceDataLayer('purchase', event));
}
function eventLog(eventName, eventData) {
const css1 = 'background: red; color: #fff; font-size: normal; border-radius: 3px 0 0 3px; padding: 3px 4px;';
const css2 = 'background-color: blue; color: #fff; font-size: normal; border-radius: 0 3px 3px 0; padding: 3px 4px;';
console.log(
'%cGTM DataLayer Event:%c' + event_prefix + eventName, css1, css2, eventData
);
}
function getPageLocation(event) {
let pageLocation = event.context.document.location.href;
if(gclidWithPageLocation) {
const name = '_gcl_aw';
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
const gclidCookie = parts.pop().split(';').shift();
const gclidParts = gclidCookie.split('.');
const gclid = gclidParts[gclidParts.length - 1];
pageLocation = pageLocation.includes('?') ? `${pageLocation}&gclid=${gclid}` : `${pageLocation}?gclid=${gclid}`;
}
}
return pageLocation;
}
async function sha256Hash(value) {
const encoder = new TextEncoder();
const data = encoder.encode(value);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashedValue = hashArray.map(byte => ('00' + byte.toString(16)).slice(-2)).join('');
return hashedValue;
}
async function ecommerceDataLayer(gtm_event_name, event) {
let hash_email;
let hash_phone;
const phone = event.data?.checkout?.phone;
const email = event.data?.checkout?.email;
if (phone) {
hash_phone = await sha256Hash(phone);
}
if (email) {
hash_email = await sha256Hash(email);
}
const customerInfo = {
customer: {
first_name: event.data?.checkout?.billingAddress?.firstName || event.data?.checkout?.shippingAddress?.firstName,
last_name: event.data?.checkout?.billingAddress?.lastName || event.data?.checkout?.shippingAddress?.lastName,
email: email,
hash_email: hash_email,
phone: phone,
hash_phone: hash_phone,
address: event.data?.checkout?.shippingAddress
}
}
dataLayer.push(customerInfo);
const dataLayerInfo = {
event: event_prefix + gtm_event_name,
page_location: getPageLocation(event),
ecommerce: {
transaction_id: event.data?.checkout?.order?.id,
value: event.data?.checkout?.totalPrice?.amount,
tax: event.data?.checkout?.totalTax?.amount,
shipping: event.data?.checkout?.shippingLine?.price?.amount,
currency: event.data?.checkout?.currencyCode,
coupon: (event.data?.checkout?.discountApplications || []).map(discount => discount.title).join(','),
items: (event.data?.checkout?.lineItems || []).map(item => ({
item_id: formattedItemId ? 'shopify_' + storeCountryCode + '_' + (item.variant?.product?.id || '') + '_' + (item.variant?.id || '') : item.variant?.product?.id,
product_id: item.variant?.product?.id,
variant_id: item.variant?.id,
sku: item.variant?.sku,
item_name: item.title,
coupon: item.discountAllocations?.discountApplication?.title,
discount: item.discountAllocations?.amount?.amount,
item_variant: item.variant?.title,
price: item.variant?.price?.amount,
quantity: item.quantity,
item_brand: item.variant?.product?.vendor,
item_category: item.variant?.product?.type
}))
}
}
dataLayer.push({
ecommerce: null
});
dataLayer.push(dataLayerInfo);
eventLog(gtm_event_name, Object.assign({}, dataLayerInfo, customerInfo));
}
Preview & Testing Shopify DataLayer
There are a few methods for testing and previewing the Shopify dataLayer.
Options 1: Using Browser Console
After connecting the data layer to Shopify, open your browser console — you’ll see all the data layer events and their parameters displayed neatly.

Options 2: Preview with Google Tag Manager Preview
Normally, you would preview the dataLayer using GTM Preview mode. However, due to Shopify’s restrictions, GTM Preview does not work on checkout pages. To work around this limitation, you can install a Chrome extension called “LeoMeasure – DataLayer Checkout & GTM Injector.” After installing you need to go to setting and add a GTM injector with your website url and GTM tracking code like following.

And finally need to check “GTM Preview for Shopify Custom Pixel”

Now normal GTM Preview with Google Tag Manager will works for checkout and non checkout all pages.

Additional Features
Depending on your theme, you may need to make a few adjustments to enable advanced events such as mini cart view, add to wishlist, quick view, and more. The following video covers all the details—just skip the first few minutes and start watching from 4:33
Finally, finally you encounter any issues, or need any kids of help you can contact Leo Measure support for assistance.
Source Code



Hi Hassan, really a good script especially since the values for new_customer are provided. Would it also be possible to include the customer lifetime value here?
Many thanks
It is possible for only for logged customer.
Hi, I’m excited about your script. But I would be interested to know where you got the information for customer.orders_count which you use to determine the new_customer?
Because with this information it would also be possible to determine the customer.total.value.
Do you have any ideas on how to adapt the script for this?
If customer is logged in then we can count customer’s orders.
Yes, we can.
et vero quas rem fugiat placeat saepe dignissimos aut. quia omnis enim ut maxime ipsam ex provident. repellendus et libero ut quia qui atque voluptas corporis officiis qui pariatur aut quidem ut nesci
Just wow!!! Anybody is docile to love it. 💝💝💝
Thanks Rajib
Hi. Thanks. How to change the product id for sku?
My merchant center uses sku.
Thank you for this, Hassan. Question, the code you provided can be used for any Shopify? or does it have to be generated from our Google Analytics account?
Yes, this code should work for any Shopify website weather it is normal Shopify or Shopify Plus
I’ve learned a lot about email marketing metrics from your blog.
Happy to know.
You can check our youtube channel for more videos this Google Analytics and tracking: https://youtube.com/@leocoder
The tips for using social proof in emails were great.
We are not clear about what you mean here. Can you please share more details so that we can help you?
Hello Hassan,
It’s really impressive what a script you’ve built here. I have the script in use and it works perfectly. Now I have seen that you also provide the script for Webpixel. However, I am missing the datalayer for new_customer. Are you planning to develop the script further?
Can you please send an email with details about info@leomeasure.com? I hope we can assist you.
Utilize these resources to enhance your website’s SEO performance effectively.
Thank you so much for your suggestion. If you need any help you can contact us.
there is a big issue in this code which is duplicate the puchase event, the add_to_cart etc
For duplicate events, one of the events is coming from the Shopify app. We recommend using the event prefix feature to resolve the problem.
Event prefix details: https://youtu.be/98w-kEKLICQ?t=1226
I cannot see add_shipping_info and add_payment_info in the datalayer 🙁
For this, you need to use Shopify customer pixel instead of additional scripts on the checkout page.
Screenshot: https://prnt.sc/vVWuNviM_GEF
If you need further details you can contact us.
Does this work with Shopify’s Checkout Extensibility update?
Yes, you need to check GitHub and use customer pixel instead of additional scripts on checkout
Screenshot: https://prnt.sc/vVWuNviM_GEF
If you need further details you can contact us.
Great code! Thanks. I have a problem when I used it with Consentmo to implement Google Consent Mode V2. As the the customer pixel works in the secure sandbox environment in Shopify’s custom pixel setup (via an iframe) isolates the iframe from the main window. This isolation prevents direct access to the main window’s cookies or JavaScript variables, including the cookie consent status. Is there any workaround to allow Google Tag Manager (GTM) container code of the checkout pages to access the cookie consent status?
Hi Nazmul, I left a comment saying that the custom pixel could not get the consent status of the main window. Now it seems I have found a solution by adding the Consentmo Template to our GTM container. Thanks.
Hello Hassan thanks for the script. I have a problem there is no section to add extra script in the checkout section.
SS https://drive.google.com/file/d/1RwBkeT3JQ96TiB_KaPgt3mgD29lMCQo0/view?usp=sharing
Yes, that has been removed and we need to use Shopify custom pixel. If you check the code in github you should find the code which you need to put as Shopify customer pixel
if you work as freelancer if any buyer message you on fiverr, upwork, freelancer or anywhere Quick Alert for Freelancers and Entrepreneurs Software will instantly notified you by Phone call.
great content, congrats!!!
so, i have a question here that is regard to catch the information in an embed form created in the Shopify-Forms app. up to this moment i can’t catch the Lead inforation to send to Facebook.
exist any code that I can integrate into this datalayer to fire with any event to catch the information fulfilled by the lead?
HiMany,
If the form was built with Shopify-Forms app that case we need to write some custom code. Please contact use with email: info@leomeasure.com or Whatsapp
For one of my client if i use the code everything working fine but recently the search bar not working. Its a shopify website,.
Please contact us with details.
I’m not sure where you are getting your information, but good topic. I needs to spend some time learning much more or understanding more. Thanks for fantastic information I was looking for this information for my mission.
Great thank you for brief video and codes
https://prnt.sc/sYIye41YfVJX
https://prnt.sc/os24vuW-vxRK
for the purchase event i added the code but not enabling checkout page data layer could you please give me advice
Please check here.