Web Storage API: LocalStorage & SessionStorage

Amir Boroumand
Jul 20, 2017 · 5 min read

In this article, we’ll cover the different approaches to client-side storage in the browser and discuss the Web Storage API in detail.

TL;DR

Does the web server need access to the data?

  • Yes -> use a cookie
  • No -> go to next question

How long should the data be kept?

  • Until user clears their cache -> use LocalStorage
  • Until the user closes their window/tab -> use SessionStorage

Cookies

Prior to HTML5, cookies were the only way to store data locally in the browser. These are typically used for targeted ads, preferences, and session management. For widespread browser support, the recommendation is to not exceed 50 cookies per domain and 4KB total cookie size.

It’s important to remember that cookies are sent in the header of every request to that domain. So anything we set client-side will be shared with the server on all subsequent requests. Sometimes this is exactly what we want, and sometimes it’s unnecessary.

Below is a screenshot of the cookies we get when visiting stackoverflow.com:

If we look at a subsequent HTTP request to the site, we’ll see that these cookies were included in the header:

Cookies are still pervasive throughout the web, but we have a few other options available to us.

For more details on cookies, check out this previous article: Let’s Talk About HTTP Cookies

LocalStorage & SessionStorage

HTML5 introduced a Web Storage API that developers can use to store data in the browser. The two implementations of those are LocalStorage and SessionStorage.

Like cookies, these are stored in key/value pairs consisting of strings.

Unlike cookies, they are not sent to the server at all. They can be cleared by the developer using JavaScript or by the user in their browser settings.

The only difference between LocalStorage and SessionStorage is the lifetime of their contents. LocalStorage items persist until they are cleared explicitly while SessionStorage items persist only during the lifetime of the tab or window.

Here are some example use cases:

  • Storing user-specific view preferences for a site that displays a lot of data and charts
  • Storing a value to identify mailing list subscribers so we don’t display a signup form for existing subscribers
  • Storing location information so we can display regional content relevant to the user
  • Storing the contents of a shopping cart while the user is browsing around

In a nutshell, this is useful for storing data that needs to be read client-side and which the server doesn’t necessarily care about.

Methods

LocalStorage and SessionStorage both extend the Storage prototype so they have the same methods.

> Object.getPrototypeOf(localStorage); 
Storage {key: function, getItem: function, setItem: function, removeItem: function…}
> Object.getPrototypeOf(sessionStorage);
Storage {key: function, getItem: function, setItem: function, removeItem: function…}

Let’s take a look at this prototype:

Storage {
key: function,
getItem: function,
setItem: function,
removeItem: function…}
clear:function clear()
constructor:function Storage()
getItem:function getItem()
key:function key()
length:(...)
removeItem:function removeItem()
setItem:function setItem() Symbol(Symbol.toStringTag):"Storage" get length:function () __proto__:Object

setItem(key, value)

localStorage.setItem(‘countryCode’, ‘us’);

getItem(key)

let countryCode = localStorage.getItem(‘countryCode’);

Check if a key exists

This is the recommended approach for checking if a key exists:

if (localStorage.getItem('countryCode') !== null) { 
let countryCode = localStorage.getItem('countryCode');
// do something with countryCode
}

Another approach is directly accessing the property:

if (localStorage.countryCode) { }

However, this approach is discouraged because empty strings are falsey in JavaScript.

Let’s take a look at an example that illustrates this point.

If we set name to an empty string, lets see how we get different answers:

localStorage.setItem('name',''); let existsCheck1 = ( localStorage.getItem('name') !== null ) ? true : false; // true let existsCheck2 = ( localStorage.name ) ? true : false;  // false

On line 1, we set name to an empty string.

On line 2, we declare a Boolean that uses the getItem() null check to determine whether the key exists. This correctly evaluates to true.

On line 3, we declare another Boolean that uses direct property access. This evaluates to false even though we have an item that has a key = name.

There’s an interesting StackOverflow discussion on the merits of each here:

removeItem(key)

localStorage.removeItem(‘countryCode’);

clear()

localStorage.clear();

Workaround for Storing Objects

We mentioned earlier that the Storage API only supports strings. Fortunately, there’s a workaround for storing objects.

We can serialize our object to a string using JSON.stringify():

let obj = { name: 'Amir Boroumand', id: 500 }; localStorage.setItem('user', JSON.stringify(obj));

To get our object back, we use JSON.parse():

obj = JSON.parse(localStorage.getItem('user'));

Size Limits

The HTML spec recommends that browser vendors allocate 5MB per domain for each storage area.

Some browsers allow this size to be configurable. In Firefox, we can go to about:config and search for dom.storage.default_quota. There is no way to adjust the quotas for Chrome/Safari/IE.

The Storage API will throw an exception when we attempt to store an item into a full area:

try { 
localStorage.setItem('max', 'Fill it up');
} catch (e) {
console.error('Error: ', e);
}
Error: DOMException: Failed to execute 'setItem' on 'Storage': Setting the value of 'max' exceeded the quota.

Security

The Web Storage API is subject to the same origin policy. This policy determines which sites can access which data based on the URL.

Pages have the same origin if the scheme, host, and port are the same.

Let’s assume a page at https://company.com/contact saves an item to LocalStorage:

localStorage.setItem('contact-date', '2017-07-21 16:00:00 UTC');

Here’s a table that illustrates if other URLs can access this item:

This can pose a challenge for sites that still serve content over both HTTP and HTTPS because the browser considers them to be different origins.

Performance

Web Storage is synchronous in nature which means it can block page rendering. Normally, this isn’t an issue because we store small pieces of data but something to keep in mind.


Originally published at www.codebyamir.com on July 20, 2017.

)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade