localStorage has long established itself as a wonderfully comfortable way to store data in the user’s browser. Many tracking implementations depend on it.
But it is not the best solution for all cases, as 7-8% of users block it (on our site at least).
I remember how excited I was when my former colleague @ruetsch presented localStorage in a team meeting at my former employer Unic in 2012 (I admit I hadn’t heard about it before). localStorage, or more precisely, “Web Storage” or “DOM Storage”, seemed a game changer. I thought: “Finally, no more cookies, hidden fields, invisible iframes, dirty URL parameters and other terribly unelegant methods!” Because those methods had been the only way to not lose all data when a user navigates from one page to another.
That may seem odd, but it is one of the characteristics (evil tongues say one of the “problems”) of the “stateless” Hypertext Transfer Protocol (HTTP). HTTP is of course the protocol by which most information is sent across the internet. “Stateless” means everything that is transmitted is “forgotten” immediately (there is no “state” that can be checked later). So even if just a tiny bit of the information from page X is needed on another page, we have to resort to those weird and labor-intense methods mentioned above.
A Tracking Example
An example for a tracking case: When the user views a product page, we pull information about this product from a server (like “is the product new”, “does it have a reduced price”, etc.) and track it into our Web Analytics tools (Google Analytics, Adobe Analytics etc.). The user may browse a few similar products and finally decide to put the product in the cart, check it out and buy it. Now ideally, we do not want to pull all this information from the server for each product interaction (the cart addition, the checkout, the order etc.) again and again as the information is unlikely to change very fast, and pulling information from servers takes longer than having it already available in the browser.
Sometimes you would be ok with pulling that info again and again from a server, but the service that is used (like Tealium’s “Hosted Data Layer” (article on that coming up)) does not allow you to pull info for more than one product per page. However, there are pages with more than just one product on them. An example is when you have 3 different products in your shopping cart. In that case you don’t want to track the first product only.
So these are typical cases where it is helpful if not necessary to store larger data sets in the browser that go beyond simple cookie IDs.
Why Cookies Are No Fun
To this day, the most common form of storing information in the client (browser) beyond a page is the cookie. However, cookies have their downsides:
- They can hold only a very limited amount of data, and that limit is different from browser to browser (you can test your limits here).
- When working with cookies, you constantly ask yourself questions like “when does it expire?” or “Is it set to be read on the subdomains also?”. These are of course useful features of cookies, but they make the easy and simple stuff more complicated than needed.
Why localStorage Is So Much Fun
localStorage vs. IndexedDB
Side note: Even though localStorage as a client-side storing technology may at some point be supplanted by the newer, more powerful IndexedDB, IndexedDB is much more complex to get into, and you need to write much more code to achieve the same result as with the lightweight localStorage. Furthermore, the browser support for IndexedDB is not as robust as with localStorage.
If localStorage is so great: Why are there still so many cookies out there?
- Some browsers block localStorage in incognito/private mode: We (Swiss marketplace siroop.ch) track localStorage support into one of our debugging variables, and we can constantly see that 7-8% of users (even when excluding Bots) do not support localStorage. This is mainly due to Safari’s “Private Mode” in which neither localStorage nor sessionStorage nor indexedDB are allowed. As most of our visitors are mobile Apple device users (that might be a Swiss distortion), localStorage blockers are a relevant part of our traffic. So we cannot rely on localStorage for critical stuff like a user id.
That being said, make sure your tracking scripts do not fail or produce errors or funny “undefined” values in your Analytics reports when localStorage is disallowed. Verify first whether localStorage can really be used in this user’s browser. Checking for ‘window.localStorage !== “undefined”‘ won’t do the job! See this discussion for more detail.
- localStorage is not transferred across (sub-)domains. Here we have an important advantage of cookies: They can be set to the main domain (e.g. “mysite.com”) and be read by all the subdomains (e.g. “subdomain.mysite.com”). localStorage can’t. Third-party cookies, although unfit for Web Analytics tracking today because most browsers block them by default, are still in wide use by advertising networks and can even be read across main domains (which allows them to follow you across the whole internet).
- It is harder to test and debug what happens without localStorage, especially if you don’t have an Apple computer with a Safari browser where you can of course simply start the Private Mode. Chrome for example currently does not support switching off ONLY localStorage, you can only block cookies AND localStorage at the same time, which is useless for the debugging of tracking scripts because you need the cookies to work to have any tracking at all in most cases (Adobe Analytics also works without cookies, Google Analytics won’t). The best of the bad solutions I have found so far is Firefox where you can type “about:config” and then toggle DOM.storage.
- localStorage works synchronously (a difference to IndexedDB), so be careful when using it to write or read larger data sets in a script where other important operations follow afterwards. Synchronously means the user has to wait until the localStorage code is completed, only then is the code after that executed. This usually is not a problem for tracking implementations where the data chunks are tiny, but still good to know.
- localStorage does not work across protocols. So if you have a website where one part is under http://yoursite.ch and another part under https://yoursite.ch, localStorage data cannot be exchanged. Nowadays a very rare case, luckily.
So with all these downsides, should I use localStorage after all?
Yes, especially if you want to persist “larger” data sets. Even a dozen or more variables are a pain with cookies – and there is no sensible alternative to localStorage apart from the above-mentioned, more complex IndexedDB which has the same downsides apart from being asynchronous. But I advise against using localStorage for:
- Data that is really important to be there for every user (like a user ID) and a 93% sample won’t cut it
- Data that needs to be transferred to or from subdomains or protocols
For these cases, cookies are still the most common option.
Other limitations or Advantages of localStorage?
What is your opinion on localStorage vs. cookies vs. others? Do you see other limitations? What do you use when? Looking forward to your feedback!