Chrome Local Storage in Extensions
Tags: javascript, chrome, extensions, api
Published: 2019-06-24 22:20:21

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](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) contains two mechanisms: localStorage and sessionStorage. LocalStorage is [similar to sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/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](https://developer.chrome.com/extensions/storage) 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](https://developer.chrome.com/extensions/manifest) 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:

```javascript
{
  "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:
```javascript
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:

```javascript
  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:
```javascript
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](https://developer.chrome.com/extensions) when developing your first extension, it is very helpful and concise. 

Thanks for reading!