LiquidBoost
← Back to library
Product page Free

Recently viewed products

Remembers products a shopper opened and shows them in a strip, using the browser only — no app, no tracking pixel.

<div id="recently-viewed" class="recently-viewed" hidden>
  <h3>Recently viewed</h3>
  <div class="recently-viewed__grid"></div>
</div>
<style>
  .recently-viewed{margin:32px 0}
  .recently-viewed__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:16px}
  .recently-viewed a{text-decoration:none;color:inherit;font-size:13px}
  .recently-viewed img{width:100%;height:auto;border-radius:6px;display:block;margin-bottom:6px}
</style>
<script>
  (function(){
    var KEY = 'recentlyViewed';
    var handle = {{ product.handle | json }};
    var list = [];
    try { list = JSON.parse(localStorage.getItem(KEY)) || []; } catch(e){}
    var others = list.filter(function(h){ return h !== handle; });
    // Save current product to the front of the list (max 8).
    try { localStorage.setItem(KEY, JSON.stringify([handle].concat(others).slice(0,8))); } catch(e){}
    var wrap = document.getElementById('recently-viewed');
    var grid = wrap.querySelector('.recently-viewed__grid');
    var toShow = others.slice(0,4);
    if(!toShow.length) return;
    Promise.all(toShow.map(function(h){
      return fetch('/products/' + h + '.js').then(function(r){ return r.ok ? r.json() : null; }).catch(function(){ return null; });
    })).then(function(products){
      products.filter(Boolean).forEach(function(p){
        var a = document.createElement('a');
        a.href = p.url;
        a.innerHTML = (p.featured_image ? '<img src="' + p.featured_image + '&width=300" alt="">' : '') +
          '<span>' + p.title + '</span>';
        grid.appendChild(a);
      });
      if(grid.children.length) wrap.hidden = false;
    });
  })();
</script>

Brings back products a visitor already showed interest in, a proven way to recover abandoned browsing. Paste near the bottom of main-product.liquid.

Notes

  • History lives in the visitor’s own localStorage, so nothing is sent to a third party and there is no cookie banner cost.
  • It fetches each product’s public /products/{handle}.js JSON, so titles, prices and images stay current automatically.
  • The block stays hidden until at least one other product is available, so first-time visitors see nothing empty.