Hartley Brody

So You Want to Build a Chrome Extension?

buzzkill-logoI should start by saying that I just released my first chrome extension this afternoon called BuzzKill and I think you’ll like it:

BuzzKill is a Chrome Extension that automatically removes all Buzz Feed content from your Facebook browsing experience.

  • "This extension has helped me reclaim hours of my day!" -Happy User
  • "I finally feel like I have my life back" -Happy User
  • "With BuzzKill installed, I can rest assured knowing that my children are safe from the most soul-sucking content on the entire internet." -Happy User

Install it now! The code is available on GitHub and I’d be happy to take pull requests, bugs or other issues on there.

The concept is really simple, and it took me about 15 minutes to write the Javascript necessary to make it work from my console. But figuring out how to package it all up as an extension took more work than I was expecting. I’ll run through the stuff I learned here.

Getting Started

The first thing to know is that extensions are built using the same technology as everyday websites. An extension is nothing more than some HTML and Javascript files, and maybe a bit of CSS for good measure. If you already know how to build websites, you should be able to get started with extensions fairly easily.

The main thing that’s different with building an extension is that the Javascript context and APIs that you usually have access to might not be available like you’re used to. On top of that, there are a bunch of new APIs you have to learn to interact with the browser. This can make it a bit unfamiliar for those used to working with Javascript in a web development context, but overall, it’s the same code you’re used to writing.

This page gives a good overview of developing and testing Chrome Extensions locally which won’t be repeated here. Let’s dive in.

The Manifest

The first piece to start with is the manifest file. This is a JSON file that basically tells Chrome what’s in the extension. It can include the name and version of the extension, as well as links to other files like icons and background pages (more on that in a bit). There are a lot of different options you can add, just start with the required fields and we’ll add more as we go.

The next step is to figure out whether your extension makes more sense as a browser action or a page action. The main difference is how they appear in the browser’s UI:

  • Browser Actions are permanently displayed to the right of the address bar. These are good if your extension can work on any website, or if the extension is website agnostic. This is probably the right option for most extensions.
  • Page Actions are only displayed on certain pages, and their icon appears inside the address bar. This is the right options for extensions that only operate on certain websites. Page Actions explicitly tell the user which websites they need permissions for.

Since it only needs to work on certain websites, BuzzKill is a Page Action. This means that we need to add the following to our manifest.json file.

  "permissions": [
  "page_action": {
    "default_title": "Extension Name",
    "default_icon": "path/to/logo.jpg",
    "default_popup": "path/to/popup.html"

The permissions array has to include the URL(s) that the extension needs access to. Make sure to include both http and https versions of the URL, if applicable.

The page_action objects contains information about the extension’s UI. default_icon is the icon that appears in the URL bar on the specified websites, and default_popup is the HTML content that appears when the icon is clicked.

Content Scripts

Since our extension will be operating on a website that we don’t control, our Javascript needs to be injected into the page by the browser. This is where the Chrome Extension docs really started to fall apart and get confusing.

There needs to be one script that runs in the background that inserts your custom code into this page. This is called programatic injection. This file basically bootstraps the rest of the extension.

Then you need the actual code used for your extension’s logic to live in another file that gets injected into the page. These two scripts are executed in totally different environments and have access to different stuff (ie Tab objects, window, document, console, etc).

The first script is run by the browser in a background window. You tell Chrome about it by adding this to manifest.json.

  "background": {
    "scripts": ["path/to/bootstrap.js"],
    "persistent": false

This script runs in a background window and has access to all of the Chrome APIs, but no access to the content on the page that’s currently being viewed in the tab. This is where you interact with the browser, telling it when to inject your code, how to initialize the extension, and a bunch of other things. You can check out my bootstrap script here.

You’ll also presumably need to add “tabs” to your permissions array in manifest.json – yes, they mix URLs in with reserved words in a single array – in order to access the tabs API.

That bootstrap script should include this code:

chrome.tabs.onUpdated.addListener(function(id, info, tab){
    chrome.tabs.executeScript(null, {"file": "path/to/extension.js"});

This says that whenever a tab is updated (ie, URL changes), show the page action icon, and inject our extension’s Javascript into the page. You can also add some custom logic in here to check the current tab’s URL, etc.

This background script is the only one that’ll have access to the current Tab object and to the chrome.* APIs, so any interaction with the browser needs to happen in here.

Once your extension’s Javascript has been added to the page, that script has access to the document, window and console of the actual page the user sees. From this script, you can interact with the DOM as you normally would in a web development context. It’s as if you were a web developer for the site in question. The only restriction is that you can’t use variables or functions that were defined in either your bootstrap script, or on the web page itself.

The Popup

So now that that you’ve got your fancy extension.js script injected into the page and it’s doing it’s thing, you probably want to allow the user to control it in some way. For BuzzKill, it’s a simple popup with a checkbox that allows the user to turn the script on or off.

The popup is just a simple HTML document that we pointed to in our manifest file under page_action["default_popup"]. We also use localStorage to store the users’s preferences, which is the same localStorage you’re used to in HTML5 web development.

It’s important to note that you can’t run inline Javascript in the popup’s HTML file, you must link to an external script, which I called settings.js. Here’s the popup.html and settings.js file for BuzzKill.

You want to make sure that your popup appears when the icon is clicked by adding this to your bootstrap.js file.

// show the popup when the user clicks on the page action.
chrome.pageAction.onClicked.addListener(function(tab) {


Since you need to split your Javascript out across multiple file, and each of those files has access to a different context, debugging can be a bit tricky. Here’s how to view the console output of the three scripts we have so far.

Background Page (ie bootstrap.js) In our example so far, we don’t have an actual background page, only a background script (ie bootstrap.js) so Chrome automatically generates a simple HTML document that embed our script. We can inspect this document to see how our background script is doing.

Head over to chrome://extensions/ to see the list of all of your extensions and then click on _generated_background_page.html next to your extension. This opens a web inspector for your background page and allows you to see what’s been printed to the console in your bootstrap script.

Content Script (ie extension.js) This is the script that has access to the website the visitor is on. Anything printed to the console in this script will end up in the visitor’s main console for them to easily see. You probably don’t want to leave many log statements in this script so that stays clean.

Popup (ie settings.js) The popup was the trickiest to debug. When you see your Page Action’s icon in the address bar, right click and choose “Inspect Popup.” There seems to be an issue with this web inspector though because Chrome would regularly crash for me if I left that open for more than a few seconds.

When in doubt, just throw an alert(); statement in and it should bubble up one way or another.

For more information, feel free to check out BuzzKill on GitHub. The code isn’t the prettiest, but I find it much easier to learn from example code than paragraphs of text, so I hope it helps you. Don’t forget to install the extension and reclaim hours of your day!