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.

sessionStorage.clear();

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
    $('#recent-products').append(productHtml);
};

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);

8 comments on “Maintaining the user journey with HTML 5 web storage”

  1. I’ve been enjoying using localStorage on a few projects lately, but I’d be enjoying it more if I could save objects as well as strings…

    What is the browser support for this like? You say you can check for browser support – what would you do in its absence?

  2. @paulhaine – in the absence of web storage you would have to fall back on using cookies. Brett Wejrowski has written a script that simulates html5 localStorage for browsers that don’t support it.

    Regarding browser support:

    The Web Storage specification is partially implemented in Internet Explorer 8, Firefox 3.5, Safari 4, Google Chrome 4 (support for the sessionStorage object was added in version 5), and Opera 10.50. As of 14 July 2010, only Opera supports the DOM Storage events.

    Dive into Javascript

  3. @paulhaine – you could always just json encode the objects (douglas crockford’s JSON-js library comes highly recommended, you can find it at https://github.com/douglascrockford/JSON-js) and save the json string.

    To add to what Emma said about falling back to cookies, you can detect browser support using Modernizr (http://www.modernizr.com/) it’ll only take a couple lines of code like this:

    if (Modernizr.localstorage){
      // do something
    } else {
      // fall back to cookie
    }

  4. @Yan – I’ve mentioned creating JSON strings and detecting browser support in my article.

    I wouldn’t always jump to use a library if you’re only using it for one purpose.

Add your comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>