Maintaining the user journey with HTML 5 web storage

The HTML 5 specification includes a web storage API for data storage in web clients. It means we can store large amounts of data, client-side, to read and write to as we like without causing the site to slow down (when compared to using cookies).

This post imagines an anonymous user visits your site and browses products whilst deciding on the one to purchase. Each product viewed is added to a ‘recently viewed’ panel. This can be stored and read from the browser’s web storage.

Types of web storage

There are two types of web storage; localStorage and sessionStorage.

localStorage is only cleared when the user agent (i.e. browser) deems it necessary for security reasons or when asked to by the user/developer.

sessionStorage can be cleared for the same reasons as localStorage but also at the end of a session, i.e. When a top-level browsing context is destroyed….

In this example I will be using sessionStorage.

Checking for browser support

if (typeof(sessionStorage) != 'undefined' ) {
    // store stuff
else {
    // you can't use web storage

From now on, we’ll assume that the browser does know about web storage.

Adding and updating

Items are stored as strings in key value pairs, for example:

storage.setItem("theFirstKey", "theFirstValue");

In this example, I want to store more information than one value for each key. We can do this by building up a JSON object of the data we want to store and calling JSON.stringify() on it when adding it to storage.

prodInfo = function() {
    var product = {};
    product.productId = productId;
    product.productName = productName;
    // ... etc
    return product;

sessionStorage.setItem("1", JSON.stringify(prodInfo()));

I only want to store the most recent ten products, so my key needs to have some count information associated with it. I do this by adding another key/value pair when the session begins:

if(sessionStorage.length == 0)
    sessionStorage.setItem("storedCount", "0");

I use this count as my key, incrementing it each time I add a new product to storage. The code so far (productExistsInStorage() has been left as an exercise for the reader):

if(!productExistsInStorage()) {

    var currentCount = parseInt(sessionStorage.getItem("storedCount"));

    // add to storage
    sessionStorage.setItem(currentCount.toString(), JSON.stringify(productInfo()));

    // update storedCount var by one
    sessionStorage.setItem("storedCount", (currentCount + 1).toString());


Removing from web storage

Items are removed from storage by referencing its key. For this example code we want to delete the product that was stored ten before the current one – the line should be added before you increment your count:

if(sessionStorage.length > 10)
    sessionStorage.removeItem((currentCount - 10).toString());

Clearing web storage

I use clear in my application for debugging purposes as I should only ever have ten items in storage at a time. It would be more important if you were only adding to and never removing from a local store. The current size that web storage can use on disk is currently set at an arbitrary 5MB.


Reading from web storage

So now we have our recently viewed products in web storage, how do we get them on the page? Loop through sessionStorage keys, grab its value and append to an HTML fragment. After the loop append the HTML fragment to the DOM (#recent-products here is an unordered list):

outputProducts = function() {
    var productHtml = '';
    for (var i = sessionStorage.length-1; i >= 0; i--) {
        var itemKey = sessionStorage.key(i);
        if(itemKey != 'storedCount') {
            var product = JSON.parse(sessionStorage.getItem(itemKey));
	    var productId = product.productId;
            var productName = product.productName;
            // ... etc
            productHtml += '<li><a href="/product/'+productId+'">'+productName+'</a></li>';
    // append to the DOM using jQuery

Further reading

Update – 17 April 2011
This solution will only work if you want to store 1 set of data. Adding another set would mess it up. Instead, store each set in an array, rather than using the storage as the array:

storage.setItem(keyForProductStore, arrayOfProducts);