Creating a recently viewed section in Shopify

In this article I’ll be showing you how I built a recently viewed section for a Shopify theme.

The basic idea is that when a user visits a product page the product’s handle is then added to an array that is then stored in local storage. I wanted to make sure this array of product handles didn’t get too long so I limited it to just 3 items by removing the last item and adding the new item to the beginning of the array.

Adding product handle to local storage

I started by adding a data attribute to the HTML of my section file that outputs the products information, which in my case was main-product.liquid. This data attribute’s value is just the handle of the product (the product’s name output in kebab casing, e.g., my-product-title).

<div class="main-product__inner container" data-product-handle="{{ product.title | handle }}">

I then created a JavaScript file called, main-product.js, which gets the items stored in local storage (or creates an empty array if there are none), gets the handle from the data attribute, and then checks to see if it isn’t already included in the viewed products array.

If the handle isn’t found in the array then I used the unshift method to add it to the beginning of the array, and then checked to see if the array was more than 3 items long.

If the viewed products array is more than 3 items long I used the pop method to remove the last item.

/**
 * Save the product to local storage when viewed
 */

// Get local storage items or set viewedProducts to an empty array
const viewedProducts = localStorage.getItem('viewed-products') ? JSON.parse(localStorage.getItem('viewed-products')) : [];
// Get the products handle
const productHandle = document.querySelector('.main-product__inner').dataset.productHandle;

// Check to see if the current product is not already in viewedProducts
// Add current product to local storage
if (!viewedProducts.includes(productHandle)) {
    // Insert handle to the beginning of the viewedProducts array
    viewedProducts.unshift(productHandle);
    // If the viewed products array has more then three items then remove the last one
    if (viewedProducts.length > 3) {
        viewedProducts.pop();
    }
    // Set local storage item
    localStorage.setItem('viewed-products', JSON.stringify(viewedProducts));
}

Creating a recently viewed section

I then created a liquid section file called, recently-viewed.liquid and corresponding JavaScript and CSS files named, recently-viewed.js and recently-viewed.css. These files are responsible for outputting the recently viewed items.

The section file is pretty basic and contains some HTML elements, which will be used later in the JavaScript to attach items to, and a simple section schema.

<div class="recently-viewed__inner container">
    <h2 class="recently-viewed__title">Recently Viewed</h2>
    <div class="recently-viewed__items"></div>
</div>

{{ 'recently-viewed.css' | asset_url | stylesheet_tag }}
{{ 'recently-viewed.js' | asset_url | script_tag }}

{% schema %}
{
    "name": "Recently Viewed",
    "tag": "section",
    "class": "recently-viewed",
    "presets": [
        {
            "name": "Recently Viewed"
        }
    ]
}
{% endschema %}

I then added the following JavaScript to the, recently-viewed.js file.

/**
 * Displays recently viewed items in local storage
 */

// Get revcently viewied items or set an empty array
const recentlyViewed = localStorage.getItem('viewed-products') ? JSON.parse(localStorage.getItem('viewed-products')) : [];
// Get DOM element to render items to
const recentlyViewedItemsEl = document.querySelector('.recently-viewed__items');

// Check to see if the recentlyViewed array is empty
// Loop through recentlyViewed array and get product information
// Render product information to the DOM
if (recentlyViewed.length > 0) {
    // Loop through viewed items
    recentlyViewed.forEach(productHandle => {
        // Send get request to Shopify API to get product information
        fetch(`${window.Shopify.routes.root}products/${productHandle}.js`)
            .then(response => response.json())
            .then(data => {
                console.log(data);
                // Renders details to the DOM
                recentlyViewedItemsEl.innerHTML += `
                    <div class="recently-viewed__item">
                        <img
                            src="${data.media[0].src}"
                            alt="${data.media[0].alt}"
                        >
                        <h2>${data.title}</h2>
                        <a href="${data.url}" class="button">
                            See Product
                        </a>
                    </div>
                `;
            });
    });
}

Firstly I set a couple of variables: recentlyViewed and recentlyViewedItemsEl. The first one contains the product handles in local storage, and the second contains a reference to the DOM element I’m attaching the items to.

// Get revcently viewied items or set an empty array
const recentlyViewed = localStorage.getItem('viewed-products') ? JSON.parse(localStorage.getItem('viewed-products')) : [];
// Get DOM element to render items to
const recentlyViewedItemsEl = document.querySelector('.recently-viewed__items');

I’m then checking to see if there are any items in the recently viewed array. If there are none then I’m using the forEach method to loop through the product handles, sending a GET request to the Shopify API for the product information, and then appending HTML to the DOM containing the product information.

// Check to see if the recentlyViewed array is empty
// Loop through recentlyViewed array and get product information
// Render product information to the DOM
if (recentlyViewed.length > 0) {
    // Loop through viewed items
    recentlyViewed.forEach(productHandle => {
        // Send get request to Shopify API to get product information
        fetch(`${window.Shopify.routes.root}products/${productHandle}.js`)
            .then(response => response.json())
            .then(data => {
                console.log(data);
                // Renders details to the DOM
                recentlyViewedItemsEl.innerHTML += `
                    <div class="recently-viewed__item">
                        <img
                            src="${data.media[0].src}"
                            alt="${data.media[0].alt}"
                        >
                        <h2>${data.title}</h2>
                        <a href="${data.url}" class="button">
                            See Product
                        </a>
                    </div>
                `;
            });
    });
}

Styling the recently viewed section

I then added some basic CSS to best match the designs of the rest of the theme.

.recently-viewed__inner {
    padding: 4rem 0;
}

.recently-viewed__title {
    margin-bottom: 2rem;
}

.recently-viewed__items {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
}

.recently-viewed__item img {
    border-radius: 8px;
}

.recently-viewed__item h2 {
    font-size: 1.25rem;
}