For my Javascript project at Flatiron School's Web Development course, my partner and I decided to build a Chrome extension. When we got the project requirement, we wanted to create something that we would actually use, and also learn about a new area that we hadn't yet explored. Since we often find ourselves needing to remind ourselves to take a break, we decided to make a break timer extension!
While we knew creating an extension would be a different challenge than other Javascript projects we'd worked on, we underestimated how difficult it would be to make the app's data persist for a sufficient amount of time. The beauty of Chrome extensions is that they allow users to access a minimal app on their toolbar, opening and closing it whenever they want. However even a straightforward challenge like a break timer was tough, since clicking away from the extension effectively kills the Javascript session, wiping away all regular variable data.
Luckily, Chrome provides its own chrome.storage API that helps solve this problem, making developing extensions feasible.
What is Local Storage?
So far at the Flatiron School, we've been exposed to some browser-storage methods such as cookies and sessions in a Rails context. The Web Storage API contains two mechanisms: localStorage and sessionStorage. LocalStorage is similar to sessionStorage in that they are both read-only, but data stored in localStorage has no expiration time, while sessionStorage gets cleared every time the page session ends (the tab is closed).
Since localStorage is persistent among multiple page sessions, it is the ideal option for saving Chrome extension data, allowing users to click off and on the extension to their heart's content.
Using Chrome's Local Storage in Your Extension
Google has developed its own chrome.storage API that provides the same storage capacity as the Web Storage API. One thing to keep in mind when using chrome.storage is that the storage space is not encrypted, so confidential customer data should not be stored.
There are a few steps you must take and things to keep in mind when implementing Chrome's storage in your extension:
Manifest
Every Chrome extension has a manifest file called manifest.json
which describes the app and provides important metadata such as its name, scripts, permissions and version. If you want to use chrome storage, you must declare the "storage" permission to your manifest.json
file. Here is a snippet from our extension:
{
"name": "break alarm",
"version": "1.0",
"description": "Be more productive.",
"permissions": ["alarms", "declarativeContent", "storage", "<all_urls>"],
"background": {
"scripts": ["helpers.js", "background.js"],
"persistent": false
},
...
}
Storage.sync
One key difference between Chrome's storage API and the Web Storage API is that Chrome offers a storage.sync
mechanism that allows user data to be automatically synced with Chrome sync. This would allow a user to access their data on a different device, assuming they have Chrome Sync enabled on their account.
So when developing your extension, you will need to decide whether you want to use storage.local
or storage.sync
. We decided to use storage.local
for our break timer extension. The main difference between the two is the storage limit: storage.local
offers about 5.2MB of data while storage.sync
's limit is about 102KB, with maximum number of items stored of 512. A nice feature of storage.sync
is that even if the user has disabled Chrome Sync, it will still work and just behave like storage.local
.
Asynchronous Calling
Another cool feature of chrome.storage is that all of its calls are asynchronous, while the localStorage in the Web Storage API is called synchronously. While in our project I found the process of getting every locally stored variable asynchronously to be annoying at times, this mechanism allows extensions to run much faster.
Setting a new object in chrome.storage is relatively straightforward. In our break timer extension, when the user clicked the "resume" button, we would set the following in local storage:
chrome.storage.local.set({ isPaused: false })
chrome.storage.local.set({'user_name': json.user_name})
chrome.storage.local.set({'phone_number': json.phone_number})
chrome.storage.local.set({'redirect_url': json.default_url})
chrome.storage.local.set({'break_time': json.default_break_time});
When calling saved objects from chrome.storage, we can use a bulk async get
function that will access multiple objects at once. Here's an example from our break timer extension:
chrome.storage.local.get(['user_name', 'phone_number', 'redirect_url',
'break_time', 'isPaused'], function(data) {
h1.textContent = data.user_name
timerInput.value = data.break_time
urlInput.value = data.redirect_url
phoneInput.value = data.phone_number
if (!data.isPaused) {
updateCountdown();
countdownInterval = setInterval(updateCountdown, 100);
isNotPausedDisplay();
} else {
chrome.storage.local.get('pausedCount', function(data) {
counterElement.innerHTML = secToMin(data.pausedCount);
});
isPausedDisplay();
}
});
Removing Items from Chrome Storage
In order to make full use of chrome.storage, it is important to understand how and when to remove stored data. In our timer extension, we had user data stored such as their preferred break time, their preferred "work" url, and their phone number for timer alerts. We wanted to persist the user's data while they were logged in so that they could set several timers and didn't have to re-enter all their settings if they returned to the extension. However when they log out, we want to remove the user's stored data from chrome.storage so that another user could log in on the same machine.
Luckily, chrome.storage makes it easy to do this! Chrome offers both a chrome.storage.local.remove
function that lets you specify which key(s) you would like to remove, and a chrome.storage.local.clear
function that will clear all data stored in the extension's local storage. Both functions have optional callback function parameters that will return on success or failure (and then runtime.lastError will be set).
Since in our extension, we wanted to remove all the user's data once they logged out of the app, we wrote a method that used the clear function with an error-catching callback:
function clearLocalStorage(){
chrome.storage.local.clear(function() {
var error = chrome.runtime.lastError;
if (error) {
console.error(error);
}
})
}
Conclusion
Overall, chrome.storage was an indispensable tool to ensure that our extension ran correctly and persisted the user data that we wanted. While building an extension seemed daunting at first, with so many new files and specifications, learning how to use chrome.storage made things so much easier. I would highly recommend heading over to Chrome's extensions documentation when developing your first extension, it is very helpful and concise.
Thanks for reading!
Top comments (7)
My understanding is that the total quota of storage.local (about 5 MB?) is shared among all extensions, so potentially in case one extension eats up 5MB, I won't be able to store my data. Is that correct? Also, since the storage API includes
.clear()
my understanding is that the scope is per extension and there is no need to namespace the settings, correct? (otherwise you would be able to clear storage area belonging to other extensions)IT'S OBVIOUS!
I'd love to take a look at your git -- I'm working on a Pomodoro timer Chrome extension using React, and working on deciding between using local storage or messaging. I haven't seen too many examples with local storage, which is what I think I'm leaning toward.
If I want to store some data for the chrome extension that stays even when the browser window is closed, what kind of storage should be useful then.
Chrome's local storage can persist when the window closes. You can use either
storage.local
orstorage.sync
to accomplish that.Where this manifest.json file should be kept? At the root directory of the application?
Hi - yes, it should be kept in the root directory. Here is more info on the manifest.json file: developer.chrome.com/extensions/ma...