By Thomas Nagl
Tracking your users’ behavior and actions on your Shopify store is essential to your marketing efforts. Unfortunately, Klaviyo's default integration only tracks "Added to Cart" events from a product page. If your collection pages include "Add to Cart" buttons for your products, those events are not tracked—meaning you have incomplete data on your users' behavior. If you want to learn more about collecting and using zero-party and first-party data, read this blog post.
The solution is to add some custom javascript to send the "Added to Cart" event to Klaviyo on collection pages via their API.
Here is a simplified example of product listings for a collection page. Each site will have a different HTML structure, but the general principle will be the same. What you're really looking for at this point is the "Add to Cart" buttons and their containers.
<div class="product">
<h3 class="product-title">{{ product.title }}</h3>
<p><a class="button add-to-cart">Add to Cart</a></p>
</div>
You'll need to add some attributes to one of the HTML elements. This is the data your custom javascript will send to Klaviyo when the "Add to Cart" button is clicked. A few notes:
-
Prepend your store's root domain to the product URL field. Shopify stores a relative path for this field, but Klaviyo needs the full, absolute URL.
-
Make sure to format your price. Shopify stores the price without decimals or currency symbols, but Klaviyo needs both of those in the data it receives.
-
Add “https:” to your image URL. Shopify stores the image URL without the protocol, but Klaviyo needs it included in the data we send.
-
Change the collections’ delimiter to something that won't conflict with your collection names. The example code below uses a vertical bar as a delimiter, however, if any of your collection names use a vertical pipe, you will need to change this to a different character.
<div class="product"
data-id="{{ product.id }}"
data-title="{{ product.title }}"
data-url="https://www.example.com{{ product.url }}"
data-price="{{ product.variants[0].price | money }}"
data-image="https:{{ product.featured_image.src }}"
data-collections="{% for collection in product.collections %}{{ collection.title }}{% unless forloop.last %}|{% endunless %}{% endfor %}">
<h3 class="product-title">{{ product.title }}</h3>
<p><a class="button add-to-cart">Add to Cart</a></p>
</div>
The last thing you'll need to do is add the below javascript to your collection template. The basic logic behind this snippet is that it adds an event listener for each "Add to Cart" button. Once clicked, it makes an ajax request to the Shopify cart in order to build out the "items" attribute that Klaviyo's "Added to Cart" event uses. After that array of items has been created, it pushes the "Added to Cart" event with the relevant product data via Klaviyo's API. You will need to customize the selectors based on the structure of your store's HTML and where you added the data attributes for each product.
<script type="text/javascript">
var _learnq = _learnq || [];
var buttons = document.querySelectorAll('.product .add-to-cart');
buttons.forEach(button => {
button.addEventListener('click', function (e) {
// Send a request to shopify for the current cart contents
var cartContents = fetch(window.Shopify.routes.root + 'cart.js')
.then(response => response.json())
.then(data => {
// Build the array of products in the cart
var itemList = [];
data['items'].forEach(function (item, i) {
var itemObj = new Object();
itemObj.variant_id = item['variant_id'];
itemObj.sku = item['sku'];
itemObj.title = item['product_title'];
itemObj.quantity = item['quantity'];
itemObj.price = item['price'] / 100;
itemObj.RowTotal = item['line_price'] / 100;
itemObj.url = 'https://www.example.com' + item['url'];
itemObj.image = item['featured_image']['url'];
itemList.push(itemObj);
});
// Push the add to cart event to Klaviyo
_learnq.push(['track', 'Added to Cart',
{
"ProductID": button.parentNode.getAttribute('data-id'),
"quantity": 1,
"Price": button.parentNode.getAttribute('data-price'),
"URL": button.parentNode.getAttribute('data-url'),
"ImageURL": button.parentNode.getAttribute('data-image'),
"Name": button.parentNode.getAttribute('data-title'),
"Categories": button.parentNode.getAttribute('data-collections').split('|'),
'items': itemList
}
]);
});
jQuery.ajax({
type: 'GET',
url: '/cart.json',
data: {},
dataType: 'json',
success: function (response) {
// Build the array of products in the cart
var itemList = [];
response['items'].forEach(function (item, i) {
var itemObj = new Object();
itemObj.variant_id = item['variant_id'];
itemObj.sku = item['sku'];
itemObj.title = item['product_title'];
itemObj.quantity = item['quantity'];
itemObj.price = item['price'] / 100;
itemObj.RowTotal = item['line_price'] / 100;
itemObj.url = 'https://www.example.com' + item['url'];
itemObj.image = item['featured_image']['url'];
itemList.push(itemObj);
});
// Push the add to cart event to Klaviyo
_learnq.push(['track', 'Added to Cart',
{
"ProductID": button.parentNode.getAttribute('data-id'),
"quantity": 1,
"Price": button.parentNode.getAttribute('data-price'),
"URL": button.parentNode.getAttribute('data-url'),
"ImageURL": button.parentNode.getAttribute('data-image'),
"Name": button.parentNode.getAttribute('data-title'),
"Categories": button.parentNode.getAttribute('data-collections').split('|'),
'items': itemList
}
]);
}
});
});
});
</script>
After this, you can test your updates and make sure it is sending the data to Klaviyo correctly. Simply go to your store with "?utm_email=testing.email@gmail.com" appended to the URL. For example, "https://www.example.com/collections/test?utm_email=testing.email@gmail.com". Then click on an “Add to Cart” button and open your new customer profile to see if the "Added to Cart" event shows up in its feed.
Once you’ve confirmed that your clicks are tracking correctly, you’ll be able to make sure all of your e-commerce marketing efforts are using the most accurate data possible.
About the author
Thomas Nagl is a web developer at SmartBug Media. He has been working with agency clients to create effective lead and sales generating websites since 2010. Thomas has experience with a number of different CMSes including Drupal, Wordpress, Shopify, and (of course) HubSpot! Read more articles by Thomas Nagl.