Storing Data in the Browser with LocalStorage

Introduction

In the early days of the web, data persistence was only possible with a server. Nowadays, through the use of LocalStorage, we can store data on clients like browsers and mobile apps without communicating with a back-end application.

In this article, we will discuss how developers can store data on the client with cookies and how LocalStorage improved that experience. We will then look at functions that store and retrieve data from LocalStorage. Finally, we'll discuss when it is appropriate to use LocalStorage.

Storing Data in the Browser With Cookies

Cookies are textual data stored in the client. They are traditionally set by the server, however, they can also be created with JavaScript code in the browser. The data in cookies are stored as key/value pairs of strings.

All cookies are sent to the server when an HTTP request is made. Cookies you make with JavaScript will also be sent to the server when an HTTP request is made. This means that the server app can inadvertently modify a cookie, causing your client app to behave unexpectedly.

With cookies, you can only store a maximum of 4KB of data on the client. For modern front-end applications, this may not be enough.

Let's see how LocalStorage allows us to create and keep data on the client-side, with much more storage space than cookies provide.

What is LocalStorage?

LocalStorage is a key/value datastore that's available on a user's browser. Like cookies, LocalStorage can only store string data for its keys and values. The datastore is only accessible to JavaScript within that domain.

Note: Each domain has access to its LocalStorage datastore. For example, LocalStorage used by https://www.stackabuse.com is separate from LocalStorage used by https://www.reddit.com.

Subdomains and different HTTP protocols (HTTP and HTTPS) all have independent datastores. For example, the LocalStorage used by https://my.example.com is completely separate from https://example.com. Likewise, https://twitter.com's LocalStorage is separate from http://twitter.com.

Having LocalStorage available per domain prevents malicious JavaScript hosted on other websites from manipulating or reading our client data that's used by our domain.

Each domain can store up to 5MB of data in LocalStorage. Also, our data isn't sent to the server when an HTTP request is made.

Data in LocalStorage has no expiration time. It can be removed via JavaScript or by clearing the browser's cache.

Now that we know what LocalStorage is, let's use its API to manage data in the browser.

How to Use LocalStorage

We can use following methods on the global localStorage object to manage client-side data:

Method Description
setItem() Add key/value in LocalStorage
getItem() Get a value from LocalStorage
removeItem() Remove item by its key
clear() Remove all items from LocalStorage
key() Get a key of an item from LocalStorage

setItem()

Use the setItem() function to store an item in LocalStorage. This function takes a key as its first argument and a value as the second argument. As mentioned earlier, both must be strings.

In your browser's console let's add an item to our localStorage:

localStorage.setItem("tech", "JavaScript");

getItem()

Use the getItem() function to retrieve data from LocalStorage. This function takes the key that was used while saving the data as an argument.

In your console, let's retrieve and print the value that was saved previously with setItem():

let techStack = localStorage.getItem("tech");
console.log(techStack);

Your console should print "JavaScript".

removeItem()

Use the removeItem() function to remove one item from LocalStorage. You need to provide the key of the item you want to delete as an argument.

Try this in your console to delete the data saved with setItem():

localStorage.removeItem("tech");

To confirm it was removed, try to retrieve it once more:

console.log(localStorage.getItem("tech"));

The console would output "null" as getItem() returns null whenever it can't retrieve an item.

clear()

To remove all the data stored in LocalStorage, use the clear() function:

localStorage.clear();

key()

The key() function allows us to retrieve the key of an item saved in LocalStorage by its index. The browser creates an integer index for each item added to LocalStorage.

As we don't generate this index, we should not use the index to retrieve keys directly. However, we can use this function to get all keys stored in LocalStorage:

for (let i = 0; i < localStorage.length; i++) {
    let storedValue = localStorage.key(i);
    console.log(`Item at ${i}: ${storedValue}`);
}

By using the length property of LocalStorage, we iterate over every index created to print all the keys we have saved in LocalStorage. We can then use these keys with getItem() to retrieve all stored data.

Now that we have covered all the functions to manage data in the user's browser, let's look at the special case of saving complex objects instead of string data.

Storing Objects in LocalStorage

LocalStorage can only use strings for its keys and values. If we try to store any other type of data, it converts it to a string before storing it. This can bring some unexpected behavior when we want to save JavaScript objects.

Let's create a person object in your browser console and save it in LocalStorage:

let person = {
    name: "John",
    age: 22
};

localStorage.setItem("profile", person);

Now, setItem() would have converted the person object to a string. When we retrieve the person like this:

console.log(localStorage.getItem("profile"));

Our browser console would show this:

Naively store an object in LocalStorage

JavaScript's object to string conversion produces [object Object]. Admittedly, getting back a string that only indicates an object was stored is not useful.

To correctly store JavaScript objects in LocalStorage, we first need to convert our object to a JSON string.

We use the built-in JSON.stringify() function for this. The resulting string of that function will contain all the properties of our JSON object. We save the output of that function when we use setItem().

Let's save the person object after stringifying it:

localStorage.setItem("profile", JSON.stringify(person));

To retrieve this data as an object we need to do two things. First, we need to use getItem() to pull it from LocalStorage. We then need to convert the JSON string into a JavaScript object.

Let's begin by taking the item from LocalStorage:

let storageProfileString = localStorage.getItem("profile");
console.log("String saved in LocalStorage", storageProfileString);

Now, convert the LocalStorage string into an object with JSON.parse() and log it to the browser's console:

let savedPerson = JSON.parse(storageProfileString);
console.log("Person object:", savedPerson);
console.log("Person's name:", savedPerson.name);

Running this code will give you the following output:

Correctly store an object in LocalStorage

Note the difference in color in the console when we first logged the string to when we logged the object. We also log the name property of person to ensure that the object's properties are still accessible.

Now that we have a strategy to expand LocalStorage's uses beyond strings, let's discuss best practices when using it.

When to Use LocalStorage

LocalStorage allows for basic persistence on your website. It's commonly used to keep data that would be convenient for the user to see even if the browser was refreshed. For example, many forms save a user's input in LocalStorage until it is submitted.

Static websites commonly use LocalStorage to store user preferences, like a UI theme. Without a web server and database to save a user preference, LocalStorage allows them to continue using your website with their customizations.

However, LocalStorage should not be used for large amounts of data. Aside from the 5MB limit which may not be enough for data-intensive applications, large data brings a performance cost when using LocalStorage.

All LocalStorage functions are synchronous operations. Therefore, if you are saving or retrieving a large chunk of data, JavaScript must complete that LocalStorage operation before it can execute other code.

Be mindful that the performance cost is increased when saving large JSON objects. The JSON.stringify() and JSON.parse() functions are also synchronous. They will block JavaScript execution until they are complete.

Never store sensitive information in LocalStorage. This includes passwords, API Keys, authentication tokens like JWTs and financial information like credit card numbers, to name a few.

Remember, every JavaScript file that is loaded on your domain has access to LocalStorage. If malicious JavaScript code is added by you or your dependencies, they can retrieve user data or tokens you use to authenticate with APIs.

Always keep sensitive data on the back-end.

Conclusion

LocalStorage is a datastore available in browsers. Data is stored as key/value pairs of strings, and each domain has access to its LocalStorage.

When storing JavaScript objects, be sure to correctly convert them to a string with JSON.stringify() before saving. As you retrieve the data, convert them to an object with JSON.parse().

When using LocalStorage, avoid processing large amounts of data as it could degrade performance because its functions are synchronous. Most importantly, be sure that no sensitive user or application data is stored in LocalStorage.

Can you think of ways to improve your application with LocalStorage?