The Web Storage API is a JavaScript based API that allows modern browsers to
store and persist data in the users browser. The Web Storage API exposes two
mechanisms for this called localStorage
and sessionStorage
. These APIs are
easy to learn and master, but can easily be abused. This article will teach you
all about the Web Storage API, why it exists, how to use it in your
applications, and most importantly when to use it and when to avoid using it.
Web Storage History
The concept of Web Storage goes back only about 10 years. The initial working draft by the W3C was published on April 23, 2009 by Ian Hickson . The Web Storage proposal called for browsers to gain the capability of storing and persisting data on the client side within the browser. Up until this point, the only mechanism available for persisting data in the browser was cookies which had many limitations as well as security concerns.
Cookies had both a size and capacity limitation. Most browsers, even today, limit the number of cookies a domain can hold. These limits range from 50 to 600, although some browsers support an unlimited amount of cookies. The bigger limitation is size. Most browsers enforce a max cookie size of 4096 bytes or 4kb. Cookies were never meant to be a data store for the browser, so this limitation makes sense.
On the security considerations side, cookies are automatically sent to the backend every time an HTTP request is made. This means that any data stored in the cookie could be compromised in transit via a man-in-the-middle attack. There are a number of other considerations that make cookies a bad choice for persistent data storage on the browser client that are outside of the scope of this article.
The Web Storage or DOM Storage proposal aimed to address the issue of persistent
data storage on the client side, i.e. the browser. The proposal called for two
unique capabilities called localStorage
and sessionStorage
.
The first, localStorage
, would allow the browser to store and persist data
that can outlive a single user session. The second, sessionStorage
, was much
more restrictive allowing data to only exist during a users active session, so
once they closed their browser, whatever was in sessionStorage
would be
deleted. The data in sessionStorage
would also be independent in different
tabs and windows as well, which is not possible with cookies.
Data storage limitations for the Web Storage API would be much larger than for cookies. Many browsers allow up to 10MB of data or more vs the 4kb limit of cookies, which represents a 1000x increase in storage capacity. Unlike cookies, data stored via the Web Storage API would only be available client side and not automatically sent to the backend.
When all was said and done the Web Storage proposal was accepted and many vendors quickly implemented it in their browsers. The simplicity of the API made it easy to learn, but gave web developers a lot of power and control when it came to storing data client-side.
Browser Compatibility
The Web Storage API proposal was accepted by virtually all browser vendors, including Internet Explorer. Today, you’ll be hard pressed to find a browser that does not support the Web Storage API.
The one exception to note is that if you are using Private Browsing in Safari.
Even though localStorage
and sessionStorage
is available, if you try to
store data you will get an exception that says that the capacity of the store
is 0. According to the spec, this is acceptable as private browsing and
persistent data can be seen as incompatible with each other. This may change in
the future for Safari, where at least the sessionStorage
store is available.
Using the Web Storage API
Both localStorage
and sessionStorage
use essentially the same API, which
lives on the window
object and exposes just a handful of methods to get the
job done. Data stored in either can only be stored as strings. Additionally,
data is stored as key-value pairs. What this means is that for each item in your
store, you will give it an identifier and then the data you wish to store. We’ll
see how that works in just a moment.
The Web Storage API is a browser feature and thus lives on the global namespace.
This means that we can access localStorage
and sessionStorage
directly or
alternatively by using window.localStorage
or window.sessionStorage
. Either
way is perfectly acceptable, and in this article for brevity I will omit
window
. The only time you would be required to use window
is if you had a
local variable called localStorage
or sessionStorage
that did something
other than what the Web Storage API intends, but I would highly recommend
against that.
Ensuring Storage is Available
Before we attempt to write data to our storage, we’ll want to ensure that our
browser has the capability to work with the Web Storage API. Like I mentioned in
the browser compatibility section, most modern browsers support the Web Storage
API, so you likely don’t need to do this, but for completeness I’ll show you how
to check. There are a number of different ways we can ensure that we have access
to localStorage
or sessionStorage
. Let’s look at some examples and
explanations below.
MDN Recommendation
The Mozilla Developer Network has an
excellent recommendation for ensuring that localStorage
or sessionStorage
is
available. I really like their approach as it will also give you a reason for
why you might not be able to use the Web Storage APIs. Their recommendation is:
function storageAvailable(type) {
try {
var storage = window[type],
x = '__storage_test__'
storage.setItem(x, x)
storage.removeItem(x)
return true
} catch (e) {
return (
e instanceof DOMException &&
// everything except Firefox
(e.code === 22 ||
// Firefox
e.code === 1014 ||
// test name field too, because code might not be present
// everything except Firefox
e.name === 'QuotaExceededError' ||
// Firefox
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
// acknowledge QuotaExceededError only if there's something already stored
storage.length !== 0
)
}
}
if (storageAvailable('localStorage')) {
// Yippee! We can use localStorage awesomeness
} else {
// Too bad, no localStorage for us
}
if (storageAvailable('sessionStorage')) {
// Yipee! We can use sessionStorage awesomeness
} else {
// Too bad, no sessionStorage for us
}
I think that Mozilla’s recommendation is the one to follow. The code is fairly simple, but most importantly it handles the various exception codes you may receive, which is a huge bonus.
Other Options
You may want something simpler that just tells you that localStorage
or
sessionStorage
is available or unavailable. Here’s a few different ways to do
it:
// Will return true if localStorage is available
!!window.localStorage
// Will return true if sessionStorage is available
!!('sessionStorage' in window)
// If localStorage is available will set a key-value pair of test:test, remove it, and return true
// If localStorage is not available will return false indicating that it is not available
try {
localStorage.setItem('test', 'test')
localStorage.removeItem('test')
return true
} catch (e) {
return false
}
My recommendation still would be to use the Mozilla way of checking for
localStorage
or sessionStorage
as it will give you an explanation of why the
storage option you are trying to access is unavailable.
Storing Data in Local Storage
Once we know that our store is available, we’re free to write and persist data.
There are a number of different ways to accomplish this. The Web Storage API
exposes the setItem()
method which is the recommended way of storing data, but
there are two other ways to do it.
// Using the setItem() method *Recommended*
localStorage.setItem('message', "I'm going to hang out in localStorage")
// Setting a new property on the localStorage object
localStorage.message2 = "I'm also going to hang out in localStorage"
// Setting a new key on the localStorage object
localStorage['message3'] = 'Hey make room, I want in on this localStorage party'
While each of the three ways is perfectly acceptable, my recommendation would be
to stick with setItem()
.
Data stored via the Web Storage API is always stored as a string. That does
not mean that we can only store strings in localStorage
, it just means that
we’ll have to do a bit of conversion when it comes to storing and retrieving our
data.
Let’s first look at a simple example: storing a number. To store a number in
localStorage
we can do the following:
// The browser will automatically convert the number 29 to a string
localStorage.setItem('age', 29)
// Explicitley convert the number 29 to a string and then store in localStorage
localStorage.setItem('age', String(29))
// Convert the age variable to a string
let age = 29
localStorage.setItem('age', age.toString())
The vast majority of browsers will automatically handle converting your number
into a string before storing it in localStorage
, but to be sure I would always
convert it myself.
Next, let’s take a look at how to store a JSON object in localStorage
.
let human = {
name: 'Ado',
age: 29,
skills: ['JavaScript', 'Go', 'Node'],
location: {
city: 'Las Vegas',
state: 'Nevada',
},
}
// If you try to do this the user key will have the value of [object Object]
localStorage.setItem('user', human)
// Using JSON.stringify we convert our JSON data to a string
// Now we can store it properly in localStorage
localStorage.setItem('user', JSON.stringify(human))
Finally, what if you wanted to store an array of data in localStorage
?
// Create an array of sports
let activities = ['Football', 'Soccer', 'Hockey']
// This will work, but will create a string with each item comma-delimited
localStorage.setItem('sports', activities)
// Store as string: "Football, Soccer, Hockey"
// Better way, like in the JSON object example will store data and keep structure
localStorage.setItem('sports', JSON.stringify(activities)) //
// Store as string: "["Football", "Soccer", "Hockey"]"
Storing complex data in localStorage
is possible. The one consideration to
keep in mind is that you will need to do some extra work to convert that data
back to a number, array, or object. Luckily, JavaScript has a lot of handy
methods to help with this like JSON.parse
to convert a string to JSON object
or parseInt()
to convert a string containing a number to a number and we’ll
see examples of that in the next section.
Retrieving Data from Local Storage
The entire point of storing data is to be able to retrieve it and in this
section we are going to look at methods on the localStorage
object that will
allow us to do just that. Just like we can store data multiple ways, we have
those same capabilities when it comes to retrieving data from localStorage
. My
recommendation here is to use the getItem()
method so that your code can
remain consistent.
// Using the getItem() method *Recommended*
localStorage.getItem('message')
// Accessing the property directly from localStorage
localStorage.message2
// Accessing the data by key from localStorage
localStorage['message3']
If all of our data were just strings, this section could be over, but since we are likely to be working with various data types, I want to cover how to convert more complex data from localStorage.
First up, let’s see how we can work with numbers.
// Retrieve the value for the key age and store it to a variable called age
let age = localStorage.getItem('age') // "29"
The age
variable at this point is a string "29"
so we cannot do any number
comparisons, use the value as an iterator, and so on. What we’re going to need
to do is convert that string value to a number.
// Get our value from localStorage
let age = localStorage.getItem('age') // "29"
// Convert it to a number
age = parseInt(age) // 29
We can also use the parseFloat()
and Number()
methods to convert a string to
a number value. Pretty easy right?
Next, let’s take a look at converting a JSON object from a string to a usable
JavaScript object. One key point to remember here is that if the object was
saved directly without first converting it to a string what you’ll get back is
[object Object]
in which case you can’t do anything with it.
let human = localStorage.getItem('human') // "{name:"ado", age: 29}"
By default, the human
variable is a string "{name:"ado", age: 29}"
. This
means that we cannot access the properties name
or age
, and if we try, we’ll
just get an undefined error. To convert this string back to a JSON object, we’ll
do the following:
let human = localStorage.getItem('human') // "{name:"ado", age: 29}"
human = JSON.parse(human)
Now our human
variable is a JavaScript option and we can access the properties
on it. Also, the age
property will be a number so you don’t have to do any
additional conversions.
Finally, let’s look at arrays. Depending on how we stored our array in
localStorage
will determine the method we use to turn the array string back
into an actual array object.
Let’s first assume we stored it directly like
localStorage.setItem("sports", sports)
.
let sports = localStorage.getItem('sports') // "football, soccer, hockey"
At this point our sports
variable is a string "football, soccer, hockey"
.
Since it is not an array we can’t access "football"
for example by doing
sports[0]
. To fix that we’ll do:
let sports = localStorage.getItem('sports')
sports = sports.split(',')
Next, let’s take a look at the case in which we stringified our array before
storing it in localStorage
like this:
localStorage.setItem("sports", JSON.stringify(sports))
.
let sports = localStorage.getItem('sports') // "["football", "soccer", "hockey"]"
Again, by default, our sports
variable is a string, but this time looks like
["football", "soccer", "hockey"]
. Since it is not an array we still can’t
access "football"
by doing sports[0]
. To fix that we’ll do:
let sports = localStorage.getItem('sports')
sports = JSON.parse(sports)
Now our sports
variable is an array and we can access individual items by
their index like sports[0]
which would return "football"
.
Updating Data in Local Storage
You may want to update data that is stored in your store. I have both good news and bad news. The bad news is that there is no way update data stored without overwriting it. This means that once you overwrite the data that is attributed to a specific key, there is no way to retrieve the original value. The good news is that overwriting the data is as simple as storing the data in the first place.
// Set data in localStorage
localStorage.setItem('message', 'You are great')
// Retrieve data from localStorage
localStorage.getItem('message') // "You are great"
// Overwrite the message key in localStorage
localStorage.setItem('message', 'You are amazing')
// Retrieve data from localStorage
localStorage.getItem('message') // "You are amazing"
As you can see, overwriting data in localStorage
is easy. You will not be
alerted that you are about to overwrite data, although you could write your own
logic for that. Once data has been overwritten it cannot be retrieved.
Deleting Data from Local Storage
Data stored in localStorage
will not be automatically deleted. There are only
a number of cases where the contents will be purged such as if a user resets all
of their browser settings and deletes history or manually goes into your domains
localStorage
via developer tools and deletes the contents. Likewise, you may
wish to occasionally remove key-value pairs that are no longer in use for your
application. The Web Storage API exposes the removeItem()
method to do just
that. The removeItem()
method deletes the key and any accompanying data that
is attached to it.
localStorage.removeItem('message')
Using the removeItem()
method will remove the key and accompanying data if it
exists. If the key does not exist, you will not get an error. Once a key-value
pair has been removed using the removeItem()
method, it is gone forever and
the contents of that specific key cannot be retrieved. You can, of course, set
new data to that key using the Web Storage API.
Deleting All Data from Local Storage
You may come across a situation in which you wish to delete all of the key-value
pairs in your localStorage
store. Luckily, there is a method called clear()
that will do just that. To delete all items currently in your localStorage
store simply call the clear()
method on your localStorage
or
window.localStorage
object.
localStorage.clear()
Calling the clear()
method will delete everything that is currently stored in
localStorage
. Be 100% certain that this is what you want to do, as there is no
undo method that will return the data, you’ll have to add it back in yourself.
Local Storage Use Considerations
The localStorage
API is more powerful than sessionStorage
because of the
data persistence across sessions. This can also be a drawback as well. Here are
some things consider when deciding what to put in localStorage
:
- Do not store any sensitive data in
localStorage
. - Any JavaScript code on your page has full and unrestricted access to
localStorage
. - The data in
localStorage
is meant to be consumed client-side, for example, managing state or figuring out where to redirect. - While many browsers support 10MB of storage or more, Firefox limits
localStorage
to 5MB, so for compatibility you should limit the amount of data you put inlocalStorage
to 5MB. - The Web Storage API is synchronous. This could affect performance if you have
a lot of calls back and forth to
localStorage
.
Storing Data in Session Storage
The Web Storage API for sessionStorage
is exactly the same as it is for
localStorage
. This means that the setItem()
method is the recommended way of
storing data in sessionStorage
as well, but there are two other ways to do it.
// Using the setItem() method *Recommended*
sessionStorage.setItem('message', "I'm going to hang out in sessionStorage")
// Setting a new property on the sessionStorage object
sessionStorage.message2 = "I'm also going to hang out in sessionStorage"
// Setting a new key on the sessionStorage object
sessionStorage['message3'] =
'Hey make room, I want in on this sessionStorage party'
The key point and difference to remember is that whatever value you store in
sessionStorage
is only available in the specific browser window or tab and
will automatically be deleted once the user closes the tab or browser window.
Additionally, even if two tabs of the same application are open, you cannot
share data between those two sessions if they are stored in sessionStorage
.
Storing non-string data in sessionStorage
is the same as localStorage
as
well. I’ll provide code examples for completeness.
To store a number in sessionStorage
we can do the following:
// The browser will automatically convert the number 29 to a string
sessionStorage.setItem('age', 29)
// Explicitly convert the number 29 to a string and then store in sessionStorage
sessionStorage.setItem('age', String(29))
// Convert the age variable to a string
let age = 29
sessionStorage.setItem('age', age.toString())
Next, let’s take a look at how to store a JSON object in sessionStorage
.
let human = {
name: 'Ado',
age: 29,
skills: ['JavaScript', 'Go', 'Node'],
location: {
city: 'Las Vegas',
state: 'Nevada',
},
}
// If you try to do this the user key will have the value of [object Object]
sessionStorage.setItem('user', human)
// Using JSON.stringify we convert our JSON data to a string
// Now we can store it properly in sessionStorage
sessionStorage.setItem('user', JSON.stringify(human))
Finally, storing an array in sessionStorage
.
// Create an array of sports
let activities = ['Football', 'Soccer', 'Hockey']
// This will work, but will create a string with each item comma-delimited
sessionStorage.setItem('sports', activities)
// Store as string: "Football, Soccer, Hockey"
// Better way, like in the JSON object example will store data and keep structure
sessionStorage.setItem('sports', JSON.stringify(activities)) //
// Store as string: "["Football", "Soccer", "Hockey"]"
Storing complex data in sessionStorage
is possible but is constrained to the
same caveats as localStorage
which means we’ll have to convert those
non-string data structures ourselves.
Retrieving Data from Session Storage
Retrieving data in sessionStorage
follows the same principles as
localStorage
.
// Using the getItem() method *Recommended*
sessionStorage.getItem('message')
// Accessing the property directly from sessionStorage
sessionStorage.message2
// Accessing the data by key from sessionStorage
sessionStorage['message3']
The non-string data structures also follow the same principles as
localStorage
. First up, let’s see how we can work with numbers.
// Retrieve the value for the key age and store it to a variable called age
let age = sessionStorage.getItem('age') // "29"
The age
variable at this point is a string "29"
so we cannot do any number
comparisons, use the value as an iterator, and so on. What we’re going to need
to do is convert that string value to a number.
// Get our value from localStorage
let age = sessionStorage.getItem('age') // "29"
// Convert it to a number
age = parseInt(age) // 29
Next up, converting a string to a JavaScript object. One key point to remember,
that I think is worth reiterating, is that if the object was saved directly
without first converting it to a string what you’ll get back is
[object Object]
in which case you can’t do anything with it.
let human = sessionStorage.getItem('human') // "{name:"ado", age: 29}"
By default, the human
variable is a string "{name:"ado", age: 29}"
. This
means that we cannot access the properties name
or age
, and if we try, we’ll
just get an undefined error. To convert this string back to a JSON object, we’ll
do the following:
let human = sessionStorage.getItem('human') // "{name:"ado", age: 29}"
human = JSON.parse(human)
Now our human
variable is a JavaScript option and we can access the properties
on it. Also, the age
property will be a number so you don’t have to do any
additional conversions.
Finally, let’s look at arrays and sessionStorage
.
Let’s first assume we stored it directly like
sessionStorage.setItem("sports", sports)
.
let sports = sessionStorage.getItem('sports') // "football, soccer, hockey"
At this point our sports
variable is a string "football, soccer, hockey"
.
Since it is not an array we can’t access "football"
for example by doing
sports[0]
. To fix that we’ll do:
let sports = sessionStorage.getItem('sports')
sports = sports.split(',')
Next, let’s take a look at the case in which we stringified our array before
storing it in sessionStorage
like this:
sessionStorage.setItem("sports", JSON.stringify(sports))
.
let sports = sessionStorage.getItem('sports') // "["football", "soccer", "hockey"]"
Again, by default, our sports
variable is a string, but this time looks like
["football", "soccer", "hockey"]
. Since it is not an array we still can’t
access "football"
by doing sports[0]
. To fix that we’ll do:
let sports = sessionStorage.getItem('sports')
sports = JSON.parse(sports)
Now our sports
variable is an array and we can access individual items by
their index like sports[0]
which would return "football"
.
Updating Data in Session Storage
Updating data in sessionStorage
follows the same principles as localStorage
.
Data that is overwritten cannot be retrieved and is lost forever.
// Set data in sessionStorage
sessionStorage.setItem('message', 'You are great')
// Retrieve data from sessionStorage
sessionStorage.getItem('message') // "You are great"
// Overwrite the message key in sessionStorage
sessionStorage.setItem('message', 'You are amazing')
// Retrieve data from sessionStorage
sessionStorage.getItem('message') // "You are amazing"
As you can see, overwriting data in sessionStorage
is easy. Just like with
localStorage
, you will not be alerted that you are about to overwrite data.
Once data has been overwritten it cannot be retrieved.
Deleting Data from Session Storage
Data is automatically deleted if the user leaves the session by closing their
browser window. If you want to manually delete specific keys, then the same
principles as the ones for localStorage
apply. The removeItem()
method is
the way to go.
sessionStorage.removeItem('message')
Using the removeItem()
method will remove the key and accompanying data if it
exists. If the key does not exist, you will not get an error. Once a key-value
pair has been removed using the removeItem()
method, it is gone forever and
the contents of that specific key cannot be retrieved.
Deleting All Data from Session Storage
Like when using localStorage
, you may come across a situation in which you
wish to delete all of the key-value pairs in your sessionStorage
store. The
process is exactly the same and has the same exact outcome and consequences.
Simply call the clear()
method and you are good to go.
sessionStorage.clear()
Note that once the user ends their session with your application, all the data
that is stored in sessionStorage
will automatically be deleted anyway.
Session Storage Use Considerations
The sessionStorage
API is meant for storing session specific data. Here are
some things consider when deciding what to put in localStorage
:
- Do not store any sensitive data in
sessionStorage
. - Any data stored in
sessionStorage
will automatically be deleted once the users ends the session by closing the browser tab or window. - Any JavaScript code on your page has full and unrestricted access to
sessionStorage
. - The data in
sessionStorage
is meant to be consumed client-side, for example, managing state or figuring out where to redirect. - While many browsers support 10MB of storage or more, Firefox limits
sessionStorage
to 5MB, so for compatibility you should limit the amount of data you put insessionStorage
to 5MB. - The Web Storage API is synchronous. This could affect performance if you have
a lot of calls back and forth to
sessionStorage
.
Other Methods and Properties Available via Web Storage API
The Web Storage API is fairly small. There are just two more methods and
properties that both localStorage
and sessionStorage
can call. The key()
method and the length
property.
The key()
method when executed on localStorage
or sessionStorage
requires
a number to be passed as a parameter. What will be returned is the corresponding
key value. Let’s see an example of how this works.
// Let's store some data in localStorage
localStorage.setItem('heroName', 'Leroy Jenkins')
localStorage.setItem('mainWeapon', 'Sword')
localStorage.setItem('secondaryWeapon', 'Bow')
localStorage.setItem('health', '100')
// Let's use the .key() method
localStorage.key(0) // Should return "heroName"
localStorage.key(2) // Should return "secondaryWeapon"
Using the key()
method with sessionStorage
works the same.
// Let's store some data in sessionStorage
sessionStorage.setItem('title', 'Avengers: Endgame')
sessionStorage.setItem('year', '2019')
sessionStorage.setItem('budget', '250000000')
sessionStorage.setItem('villain', 'Thanos')
// Let's use the .key() method
sessionStorage.key(1) // Should return "year"
sessionStorage.key(3) // Should return "villain"
A very important thing to note is that the order of the keys cannot be
guaranteed and is left to the browser to decide how and in what order to store.
For this reason, it is not recommended that you rely on the key()
method to
get you the exact key you are looking for. The most common use case on the other
hand, would be to give you a list and name of all the keys available in either
localStorage
or sessionStorage
. I’ll show you how to do that once we learn
about the length
property.
The length
property returns the number of data items that are stored in either
localStorage
or sessionStorage
.
// Let's store some data in localStorage
localStorage.setItem('name', 'Ado Kukic')
localStorage.setItem('city', 'Las Vegas')
localStorage.setItem('state', 'Nevada')
localStorage.setItem('country', 'USA')
// Let's use .length to see how many items we have in localStorage
localStorage.length // Should return 4
Likewise, we can do the same with sessionStorage
. Here’s an example:
// Let's store some data in sessionStorage
sessionStorage.setItem('name', 'Klaus')
sessionStorage.setItem('type', 'Dog')
sessionStorage.setItem('breed', 'Siberian Husky')
// Let's use .length to see how many items we have in sessionStorage
sessionStorage.length // Should return 3
As promised earlier, I will show you how to combine the length
property and
key()
method to display a list of all current keys stored in the
localStorage
of your application. The code is as follows:
// Get the length of our localStorage
let items = localStorage.length
// Create a loop that runs once for every item in localStorage
for (let i = 0; i < items; i++) {
// Print out the key value of the data
console.log(localStorage.key(i))
}
If you wanted to print out the actual key-value pair, that can be done easily as
well. In this example, we’ll use sessionStorage
. We’ll also optimize our code
a little bit.
// Create a loop that runs once for every item in sessionStorage
for (let i = 0; i < sessionStorage.length; i++) {
let key = sessionStorage.key(i)
let value = sessionStorage.getItem(key)
// Print out the key and data
console.log(`The key ${key} has the value of ${value}`)
}
Further Reading
This article was pretty exhaustive in covering the entire Web Storage API and use cases, but if you would like to learn more about the spec, browser compatibility, or history check out the following resources:
Conclusion
This article covered everything there is to know about the Web Storage API. The
web is quickly evolving and new features are proposed and added regularly. The
Web Storage API is one of the fundamental features of the modern browser and I
hope that this article can be a great reference point when working with
localStorage
and sessionStorage
in your applications.