Learn the most useful Chrome APIs by creating Block Site Chrome extension
Tags: chrome, extension, javascript, tutorial
Published: 2020-07-30 12:50:35

---
title: Learn the most useful Chrome APIs by creating Block Site Chrome extension
published: true
description: Tutorial on how to create Block Site Chrome extension, teaches you about permissions and APIs.
tags:
- chrome
- extension
- javascript
- tutorial
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/hit5j4j8njh2fbfolugh.jpg
---

This article will explain you how to use the most useful Chrome APIs by creating a simple Chrome extension called **Block Site**.

**Agenda:**

- the APIs you will learn in this tutorial are called **"storage"** and **"tabs"**
- the full list of APIs available to Chrome extensions is [here](https://developer.chrome.com/extensions/api_index)
- **Block Site**, which we are about to create to learn and practice the two APIs, is available [here](https://github.com/penge/block-site)

## Introduction

**Block Site** is a simple Chrome extension that improves your productivity by blocking the access to time-consuming websites (like during the working hours) as you specify in **Options**. **Block Site** is by default disabled and doesn't block any website until you say so in **Options**.

**Options** refers to **"options_page"** which the extension can have. To open **Options**, generally you **right-click** on the extension icon in the toolbar and choose **Options** from the menu. The same will apply to **Block Site**.

**"storage" API** will be needed to store the websites user wants to block the access to, to boost his productivity, and it will also be used to store an option to quickly disable or enable the blocking at any given moment.

**"tabs" API** will be needed to get the tab **url** we are trying to open, and based on whether the domain is on the blocked list or not, we close the tab instantly, or let it proceed.

Let's now create the extension **Block Site**.

## First steps

```
$ mkdir block-site
$ cd block-site
$ touch manifest.json
```

We have now created a new folder called `block-site` and prepared a file `manifest.json` which every extension has to have.

Update `manifest.json` to contain following:

```json
{
  "manifest_version": 2,
  "name": "Block Site",
  "description": "Blocks access to time-consuming websites (as you specify) to improve your productivity.",
  "version": "1.0",
  "options_page": "options.html",
  "permissions": ["storage", "tabs"],
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  }
}
```

The structure of this file is explained [here](https://developer.chrome.com/extensions/manifest). Any other fields besides **"manifest_version"**, **"name"** and **"version"**, are optional and we add them as needed.

**Explanation:**

- **"options_page"** is a page to open when you **right-click** the extension in the toolbar, and select **Options** from the menu. In our case, we will use this page to set a list of websites to block, and also to easily enable/disable the blocking. 

- **"permissions"** lists permissions needed by the extension. It can be requesting API access as in our case, or also a match pattern. More about possible options [here](https://developer.chrome.com/extensions/declare_permissions). Permissions are requested by the extension when installing. Based on the requested permissions, Chrome may display a warning as explained [here](https://developer.chrome.com/extensions/permission_warnings).

- **"background"** sets the script to be run in the background. In our case, it will be a place where we put the main logic to stop the blocked websites from opening. Because Chrome extensions are event-based, background script is a good place to put event-based scripts, especially if they don't require an UI (like blocking the websites). It's also a good place to put any heavy calculation that could slow down the UI. As you can see, the background is set to be no persistent. That means, when not needed, the script is unloaded from memory. More about background scripts [here](https://developer.chrome.com/extensions/background_pages).

## Create **Options** page (use **"storage"**)

Create `options.html` and give it a simple markup like this:

```html
<!DOCTYPE html>
<html>
<head>
<title>Block Site</title>
</head>
<body>

<h1>Block Site</h1>

<textarea id="textarea" rows="10" cols="30" spellcheck="false"></textarea>
<br>

<button id="save">Save</button>
<strong>Enabled?</strong><input id="checkbox" type="checkbox">

<script src="options.js"></script>
</body>
</html>
```

The UI is pretty simple. We have 3 elements:

- `#textarea` to specify the websites to block
- `#save` button to save the modified `#textarea`
- `#checkbox` to enable or disable the blocking

Create `options.js` and give it this content:

```js
const textarea = document.getElementById("textarea");
const save = document.getElementById("save");
const checkbox = document.getElementById("checkbox");

save.addEventListener("click", () => {
  const blocked = textarea.value.split("\n").map(s => s.trim()).filter(Boolean);
  chrome.storage.local.set({ blocked });
});

checkbox.addEventListener("change", (event) => {
  const enabled = event.target.checked;
  chrome.storage.local.set({ enabled });
});

window.addEventListener("DOMContentLoaded", () => {
  chrome.storage.local.get(["blocked", "enabled"], function (local) {
    const { blocked, enabled } = local;
    if (Array.isArray(blocked)) {
      textarea.value = blocked.join("\n");
      checkbox.checked = enabled;
    }
  });
});
```

We can see `chrome.storage.local` being used, which is made available by having the **"storage"** permission.

When we click on `#save`, we save the list of blocked sites in `#textarea` under the key `blocked`. Before saving them, we remove any empty lines or trailing whitespaces.

Example on how the list of blocked sites in `#textarea` can look like:

```
facebook.com
instagram.com
youtube.com
twitter.com
reddit.com
```

When we click on `#checkbox`, we save the boolean under the key `enabled`, to tell if the blocking should be enabled or not.

When the page is loaded, we read `blocked` and `enabled`, and set the UI accordingly.

## A closer look on **"storage"**

Using **"storage"** made `chrome.storage.local` available, but what is it actually? And is that all?

It turns out, **"storage"** gives us access one step further, to `chrome.storage` which is documented [here](https://developer.chrome.com/extensions/storage).

`chrome.storage` is similar to `localStorage`, in terms of its API and storage limitations. The main benefit comes from it being **asynchronous** and having an `onChanged` listener that can be used to synchronize the UI or otherwise react to changes in data.

`chrome.storage` gives us 3 storage areas:

- `chrome.storage.local` that is best for storing the data locally
- `chrome.storage.sync` that supports to store and synchronize (although very limited in size) the data across other computers where the extension is installed and same Google Account is used
- `chrome.storage.managed` which is like read-only area for administrator purposes only

The most commonly used storage out of these three is `chrome.storage.local`.

The most common methods across these storages are `get`, `set`, and `remove`. See the documentation [here](https://developer.chrome.com/extensions/storage).

## Create **Background** script (use **"tabs"**)

Now when we have the Options page ready, which can set `blocked` (array of websites to block) and `enabled` (boolean if blocking should be applied or not), it is time to work with these in the background. 

Create `background.js` and give it this content:

```js
chrome.runtime.onInstalled.addListener(function () {
  chrome.storage.local.get(["blocked", "enabled"], function (local) {
    if (!Array.isArray(local.blocked)) {
      chrome.storage.local.set({ blocked: [] });
    }

    if (typeof local.enabled !== "boolean") {
      chrome.storage.local.set({ enabled: false });
    }
  });
});

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo) {
  const url = changeInfo.pendingUrl || changeInfo.url;
  if (!url || !url.startsWith("http")) {
    return;
  }

  const hostname = new URL(url).hostname;

  chrome.storage.local.get(["blocked", "enabled"], function (local) {
    const { blocked, enabled } = local;
    if (Array.isArray(blocked) && enabled && blocked.find(domain => hostname.includes(domain))) {
      chrome.tabs.remove(tabId);
    }
  });
});
```

At the top we can see `chrome.runtime` being used. More about this API [here](https://developer.chrome.com/extensions/runtime). List of all available APIs [here](https://developer.chrome.com/extensions/api_index). And list of all possible permissions [here](https://developer.chrome.com/extensions/declare_permissions).

As we can see, not every API requires a permission. Some APIs are generally available in extensions, like `chrome.runtime`.

`chrome.runtime.onInstalled.addListener` calls a given callback any time the extension is installed or updated. What we do here, we simply check if `blocked` and `enabled` are of a correct format, and if not, we reset them.

The more interesting, is the use of `chrome.tabs`. Most of this API is generally available as well.

## A closer look on **"tabs"**

`chrome.tabs` which is described [here](https://developer.chrome.com/extensions/tabs), opens many options like creating a new tab, updating an existing tab, or reacting to various events about tabs. Most of the API is generally available, and doesn't require a **"tabs"** permission.

We are using **"tabs"** permission to get the access to `url` and `pendingUrl` inside the `onUpdated` event. This way, we can detect if the address we try to open matches any website from the `blocked` list, and if yes, we close the tab instantly as a way of blocking the access.

`pendingUrl` is quite new (available since Chrome 79), and it captures the url we indent to open before the tab committed to it. `pendingUrl` precedes `url`. `url` is more like a fallback. One tab can go through many events.

To close the tab that would navigate to a blocked site, we use `chrome.tabs.remove` and provide it with a `tabId`.

## Testing **Block Site**

**Block Site** is now ready to test.

Open `chrome://extensions` in a new tab and navigate to `block-site` folder to load the extension. If no errors were made, extension should be successfully loaded.

Open any website you'd like to block, see that it works as usual.

Now, **right-click** on **Block Site** icon and select **Options** to open. Type in the website you would like to block and hit **Save** and **Enabled**.

Now, try to open the blocked site again. It should not be possible! Try disabling the blocking via **Options** and playing around with the used APIs by checking the values from the console.

---

Thank you very much for reading the article. I hope you enjoyed it and it left you full of excitement to continue learning. Cheers!

**A summary of used resources:**

- [Manifest file](https://developer.chrome.com/extensions/manifest)
- [List of all Chrome APIs](https://developer.chrome.com/extensions/api_index)
- [Chrome Runtime API](https://developer.chrome.com/extensions/runtime)
- [Chrome Storage API](https://developer.chrome.com/extensions/storage)
- [Chrome Tabs API](https://developer.chrome.com/extensions/tabs)
- [All possible permissions](https://developer.chrome.com/extensions/declare_permissions) and [all possible warnings related to them](https://developer.chrome.com/extensions/permission_warnings)
- [All about Background scripts](https://developer.chrome.com/extensions/background_pages)
- [Block Site on GitHub](https://github.com/penge/block-site) - give it a like pls! :)

**Here are the extensions I made on Web Store:**

- [**Skip Ad**](https://chrome.google.com/webstore/detail/skip-ad/bimlffinhbdhgpomhngmnhidjgnfcnoc) (article [here](https://dev.to/penge/chrome-extension-that-skips-youtube-ads-steps-how-to-create-it-3ibp))
- [**My Notes**](https://chrome.google.com/webstore/detail/my-notes/lkeeogfaiembcblonahillacpaabmiop)
- [**Block Site**](https://chrome.google.com/webstore/detail/block-site/bjcnpgekponkjpincbcoflgkdomldlnl)