Run scripts on every page

Create your first extension that inserts a new element on the page.

Overview

This tutorial builds an extension that adds the expected reading time to any Chrome extension andChrome Web Store documentation page.

Reading time extension in the extension's Welcome page
Reading time extension on the extension's Welcome page.

In this guide, we're going to explain the following concepts:

  • The extension manifest.
  • What icon sizes an extension uses.
  • How to inject code into pages usingcontent scripts.
  • How to use match patterns.
  • Extension permissions.

Before you start

This guide assumes that you have basic web development experience. We recommend checking out theHello world tutorial for an introduction to the extension development workflow.

Build the extension

To start, create a new directory calledreading-time to hold the extension's files. If youprefer, you can download the complete source code fromGitHub.

Step 1: Add information about the extension

The manifest JSON file is the only required file. It holds important information about theextension. Create amanifest.json file in theroot of the project and add the following code:

{"manifest_version":3,"name":"Reading time","version":"1.0","description":"Add the reading time to Chrome Extension documentation articles"}

These keys contain basic metadata for the extension. They control how the extension appears on the extensions page and, when published, on the Chrome Web Store. To dive deeper, check out the"name","version" and"description" keys on theManifest overview page.

💡Other facts about the extension manifest

  • It must be located at theroot of the project.
  • The only required keys are"manifest_version","name", and"version".
  • It supports comments (//) during development, but these must be removed before uploading your code to the Chrome Web Store.

Step 2: Provide the icons

So, why do you need icons? Althoughicons are optional during development, they arerequired if you plan to distribute your extension on the Chrome Web Store. They also appear in otherplaces like the Extensions Management page.

Create animages folder and place the icons inside. You can download the icons onGitHub. Next, add the highlighted code to your manifest to declare icons:

{"icons":{"16":"images/icon-16.png","32":"images/icon-32.png","48":"images/icon-48.png","128":"images/icon-128.png"}}

We recommend using PNG files, but other file formats are allowed, except for SVG files.

💡Where are these differently-sized icons displayed?

Icon sizeIcon use
16x16Favicon on the extension's pages and context menu.
32x32Windows computers often require this size.
48x48Displays on the Extensions page.
128x128Displays on installation and in the Chrome Web Store.

Step 3: Declare the content script

Extensions can run scripts that read and modify the content of a page. These are calledcontentscripts. They live in anisolated world, meaning they can make changes to their JavaScript environment without conflicting with their host page or other extensions' content scripts.

Add the following code to themanifest.json to register a content script calledcontent.js.

{"content_scripts":[{"js":["scripts/content.js"],"matches":["https://developer.chrome.com/docs/extensions/*","https://developer.chrome.com/docs/webstore/*"]}]}

The"matches" field can have one or morematch patterns. These allow the browser toidentify which sites to inject the content scripts into. Match patterns consist of three parts:<scheme>://<host><path>. They can contain '*' characters.

💡Does this extension display a permission warning?

When a user installs an extension, the browser informs them what the extension can do. Content scripts request permission to run on sites that meet the match pattern criteria.

In this example, the user would see the following permission warning:

Permission warning the user will see when installing the Reading time extension
Reading time permission warning.

To dive deeper on extension permissions, seeDeclaring permissions and warn users.

Step 4: Calculate and insert the reading time

Content scripts can use the standardDocument Object Model (DOM) to read and change thecontent of a page. The extension will first check if the page contains the<article> element.Then, it will count all the words within this element and create a paragraph that displays the totalreading time.

Create a file calledcontent.js inside a folder calledscripts and add the following code:

functionrenderReadingTime(article){// If we weren't provided an article, we don't need to render anything.if(!article){return;}consttext=article.textContent;constwordMatchRegExp=/[^\s]+/g;// Regular expressionconstwords=text.matchAll(wordMatchRegExp);// matchAll returns an iterator, convert to array to get word countconstwordCount=[...words].length;constreadingTime=Math.round(wordCount/200);constbadge=document.createElement("p");// Use the same styling as the publish information in an article's headerbadge.classList.add("color-secondary-text","type--caption");badge.textContent=`⏱️${readingTime} min read`;// Support for API reference docsconstheading=article.querySelector("h1");// Support for article docs with dateconstdate=article.querySelector("time")?.parentNode;(date??heading).insertAdjacentElement("afterend",badge);}renderReadingTime(document.querySelector("article"));

💡Interesting JavaScript used in this code

Step 5: Listen for changes

With the current code, if you switch articles using the left navigation, thereading time is not added to the new article. This is because our site isimplemented as a Single Page Application (SPA) that performs soft navigationsusing theHistory API.

To fix that, we can use aMutationObserverto listen for changes and add the reading time to new articles.

To do this, add the following to the bottom ofcontent.js:

Warning: UsingMutationObserver can have a performance cost, so use themsparingly and only observe the most relevant changes.
constobserver=newMutationObserver((mutations)=>{for(constmutationofmutations){// If a new article was added.for(constnodeofmutation.addedNodes){if(nodeinstanceofElement &&node.tagName==='ARTICLE'){// Render the reading time for this particular article.renderReadingTime(node);}}}});// https://developer.chrome.com/ is a SPA (Single Page Application) so can// update the address bar and render new content without reloading. Our content// script won't be reinjected when this happens, so we need to watch for// changes to the content.observer.observe(document.querySelector('devsite-content'),{childList:true});

Test that it works

Verify that the file structure of your project looks like the following:

The contents of the reading time folder: manifest.json, content.js in scripts folder, and images folder.

Load your extension locally

To load an unpacked extension in developer mode, follow the steps inDevelopmentBasics.

Open an extension or Chrome Web Store documentation

Here are a few pages you can open to see how long each article will take to read.

It should look like this:

Reading time running on the Welcome page
Extension Welcome page with the Reading time extension

🎯 Potential enhancements

Based on what you've learned today, try to implement any of the following:

  • Add anothermatch pattern in the manifest.json to support otherchrome developerpages, like for example, theChrome DevTools orWorkbox.
  • Add a new content script that calculates the reading time to any of your favorite blogs ordocumentation sites.
Hint: You can use DevTools toinspect DOM elements.

Keep building

Congratulations on finishing this tutorial 🎉. Continue building your skills by completing othertutorials on this series:

ExtensionWhat you will learn
Focus ModeTo run code on the current page after clicking the extension action.
Tabs ManagerTo create a popup that manages browser tabs.

Continue exploring

We hope you enjoyed building this Chrome extension and are excited to continue your Chromedevelopment learning journey. We recommend the following learning path:

  • Thedeveloper's guide has dozens of additional links to pieces of documentationrelevant to advanced extension creation.
  • Extensions have access to powerful APIs beyond what's available on the open web.TheChrome APIs documentation walks through each API.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2022-10-04 UTC.