How to make a Chrome browser extension from scratch | Understanding Chrome extension anatomy

Sumit Kumar Arora
Frontend Weekly
Published in
7 min readJan 31, 2018


As a student at the University of Chicago, I regularly use the university’s Canvas portal to access class materials. However, this portal, along with a few uChicago portals require the user to take some unnecessary navigational steps to download files. So, I decided to make a Chrome extension that allows the user to download all the course material in a single click, right from the course page, without having to go to each module and then click each file link separately.

To do this, I designed my extension in such a way that it will scrape the current page and all the linked webpages to fetch a list of available downloads links. And then display the module-wise download buttons to the end-user, to enable bulk downloading of all the files with a single click. In this post, I will share the learning from making my first Chrome extension.

Building blocks of a Chrome browser extension

To create a Chrome extension, you need to have following components:

  1. manifest.json file
  2. Popup page
  3. Content script
  4. Events page

Let’s discuss each of the component one-by-one.

Create Manifest.json

This file is basically some metadata in json format that contains basic properties about our extension, such as extension’s name, description, version number etc. For more information about manifest file, read Google’s Manifest File Format documentation.

At a bare minimum, our extension needs below content:

“manifest_version”: 2,
“name”: “UC Grabber”,
“version”: “0.1”

manifest_version has to be 2. Since manifest version 1 has been deprecated in Chrome 18. (read more here)

Let’s add a bit more jazz in our manifest by supplying a plain description, an icon and a popup window that will open when user click on the extension icon.

"manifest_version": 2,
"name": "UC Grabber",
"version": "0.1",

"browser_action": {
"default_icon": "images/icon.png",
"default_popup": "html/popup.html",
"default_title": "Grabber for uChicago Canvas!"
  • As a good practice, we will keep images, scripts and html files in their respective directories and refer to them with a relative URL.
  • icon.png will be a 19-px square PNG file. Use any file that you want to be used as the icon for your extension.
  • popup.html: Simple html file whose content will be populated inside the small window that pops-up when a user clicks on the extension icon.

Let’s create a sample ‘popup.html’ file with just ‘Hello world!’ inside it and test our extension. To test the extension in chrome, click the hamburger menu, go to More tools -> Extensions. Enable “Developer mode” on the top-right and click “Load Unpacked Extension” button, now browse to the main directory where manifest.json is located, click ok.

and Voila! our cute little extension is up and running.

Create Content script

As our script needs to access content inside the webpage loaded by user, it needs a content script. This script will be equivalent to a JavaScript file that is loaded by the browser as part of the webpage. You could read more about content scripts here.

For our purpose, our content script will check the webpage to see if the URL of the current page belongs to our target website, which happens to be Canvas portal URL in this case. If it is Canvas URL, content script will fetch downloadable links from the webpage and pass it onto the popup.html page so that user can be shown the options to download the desired files.

Note: Content script can’t directly modify the content of it’s parent extension, but we can always pass the desired download content to the parent extension.

Popup reads events only when it is active, hence message passing from content script is not feasible
So, we make the content script talk to the background(events) page, which in turns saves all the information for popup page

We will connect the content script with the manifest file. By passing in the “matches” key, we ensure that we call our content.js script only when the URL matches

“manifest_version”: 2,
“name”: “UC Grabber”,
“version”: “0.1”,

“permissions”: [

“browser_action”: {
“default_icon”: “images/icon.png”,
“default_popup”: “html/popup.html”,
“default_title”: “Grabber for uChicago Canvas!”

“content_scripts”: [
"matches": [
"js": ["scripts/content_canvas.js"]

In our project, content script will scrape the webpage and fetches the desired URLs. The exact scraping expression will depend upon the webpage that you want to scrape, and how the desired url is nested among html tags.

Of course, you can you any of your favorite JavaScript library to make your content scripts more efficient. As an added feature, I made my extension to be able to insert download buttons in the webpage itself. So, I used jQuery to manipulate DOM based on my needs.

Create Event Page

Event pages are the single long-running scripts used to manage certain tasks and states. Chrome supports and recommends using event pages since Chrome 22. Event pages carry advantage over background pages that they are unloaded when they are not active, hence consuming lesser memory. This performance optimization becomes significant, especially on low-power devices.

Event pages will get loaded in below situations:

  1. Extension is first installed or is updated to a new version.
  2. An event is dispatched.
  3. Content script sends a message.
  4. Popup view calls background page.

Why do we need events script ?

Overview of scripts

In our extension, the content script scrapes the webpages and creates a JavaScript object of the download file titles and download links. This JavaScript object is sent to the popup which is supposed to show the download buttons to the end-user. But there is one problem! The popup page can only listen to the content script only if the popup window is open. And as you can imagine, the end-user might not want to keep waiting for the result with popup window open all the time (Note: popup window gets closed when user switches to another tab). So, we need an intermediary script between content and popup, and the events script does just that.

In our extension, the events page will temporarily save the download information scraped by content script in a local JavaScript object that neatly stores download information returned by each tab organized by respective tab id. So that when popup view is opened, it asks for scraping status of the content script to the events script. If the scraping is done, the events script simply checks the tab id for the tab for which popup window is requesting scraping status and simply returns the stored information to popup. Similarly, if scraping is ongoing, the events script has to maintain status for the respective tab so that end-user can be shown some wait-screen animation, such as one in the next section.

Create Popup Page

The popup window is the “front-end” of your extension. This is the interface that the user sees and interacts with. Simply put, a popup window is just an HTML file that is displayed each time end-user clicks on the icon of your extension. In our project, this popup window gets the start scraping request from user, shows the available download options to the user, and communicates with the events page to fetch scraping status and results. Also, to make your extension appealing, you can also add certain animations in terms of loading, waiting, results etc. For example, in my extension, user sees below gif file as waiting screen, when the scraping is ongoing at the content script.

wait screen while to indicate the content script is scraping content for this webpage (gif source: Google Images)

Note that this animation is actually a gif file, that can be stored as part of your extension, or you could also render an image hosted elsewhere on the internet.

And by utilizing the “matches” parameter of the manifest file. We can also show some attractive screen to the user for the websites that are not supported by the extension.

indication that the current website is not supported by our extension (gif source: Google Images)

With that we have the knowledge of all the necessary concepts required to build a Chrome Browser Extension. When you are done with unit testing, you can publish your extension using the Official Chrome Developer Dashboard. To activate the developer account, you need to pay a one-time activate fee of 5$. This should set you up for publishing up to 20 extensions on Google Chrome Web Store.

The extension that I made is available here on Google Chrome Web Store. The complete source code is available on the project repository on my GitHub. You can also check out the extension in action on this post.

With that, I hope I could inspire you to start working on a project of your own. Thank you for reading this post! And I will see you in the next one! :)