How to create a Chrome New Tab Page extension

Michael Flores
6 min readMay 3, 2021


Chrome’s Extension API allows you to customize a broad surface area of browser behaviors: the look and feel of web pages, modifications to the behavior of sites, and augmentation of browser features.

One of the browser features you can augment are certain browser-provided pages: bookmarks, history, and the New Tab Page. This page is viewed every time you open a new tab, unless the user has opted in to other behavior.

Given how frequently it’s visited, it presents some of the most valuable real estate that an extension can override. This post will explore creating a Chrome extension that provides a unique New Tab Page and how to deploy it to the Chrome Web Store.

We have a few steps to accomplish to create a New Tab Page replacement and get it onto the Chrome Web Store:

  1. Create and test our extension
  2. Get a Chrome Web Store developer account
  3. Get the package published to the Chrome Web Store

Creating a Chrome extension

What’s an extension made of?

A Chrome extension is roughly an arbitrary set of HTML, CSS, and JavaScript. If that sounds like a web page, that’s because it is. That’s essentially the framework for the Chrome extension platform. The vision of the platform is to build on web technologies so that there is a stable, secure foundation that has a broad developer base capable of taking advantage of it.

A basic repo for an extension has the following files:

  • index.html
  • manifest.json

That’s it. This is the basic extension model: an extension’s manifest.json is read, and that manifest has a pointer to some application entry point which the browser will load.

Walkthrough: Creating a Chrome extension

Let’s make an extension manifest that sets the New Tab Page to a new value, which will be our index.html.

These are the minimum fields for overriding the New Tab Page, and most apply to any Chrome extension.

  • name: the name of your application, which appears everywhere your extension is referenced by name in the Chrome UI. This includes on hover in the extension bar, and in the extension page.
  • description: appears in the user’s Chrome extension page listing for your extension once installed
  • default_icon: the icon for your application. This is the default, and other sizes can be specified which will be used in different contexts. For now we’ll just set a default icon.
The Extensions management page in Chrome. Your extension’s name, description, and icon are used here and in the extension bar when the user has added it there.
  • chrome_url_overrides: a list of URLs that the extension will override. Note that while the name implies you can override more than one page in your extension, you can only override one Chrome URL in a given extension. You can specify newtab , bookmarks , or history and provide the path to your HTML entry point.
  • version: a Semantic Version number that represents a particular release of the extension. After publishing, you’ll begin incrementing this when you want to make app updates.
  • manifest_version: the manifest API that your manifest is targeting. Manifest v3 was released at the beginning of 2021 and isn’t yet required, but does offer enhanced capabilities for extensions so I recommend using v3 for a new extension. This example sets it to v2 but everything here would also be valid in v3. Some extension features like background pages or network request interception work differently in v3, but New Tab Page overrides are the same.

With this manifest, Chrome will load index.html every time the new tab page is opened. That’s important to consider, because this action occurs with very high frequency in a user’s browsing session. This means our extension needs to load quickly and not make the user feel like something is slowing down their navigation at all.

So, we’ve got a blank index.html loading right now (great performance on that one), but now we want to use something more meaningful to create our application UI right? Turns out this is no different than rendering any other index.html, so we can use any of our favorite frameworks. Here’s what the entry point might look like in React — it’s a typical React index file:

Note that in your own app you should consider the startup time of your preferred framework when choosing to make a NTP extension with it. This startup time will occur every time the NTP is opened. The NTP is reinitialized on each open, and your extension code starts from step 0 each time. Nothing will be able to display on the page until the entry point file is loaded and the JS of the framework parsed and run, so be sure that you’re testing on various CPU throttle levels that represent your users’ devices.

Testing the extension

Now is a good time to see if we can run our sample index in the actual browser. We need to tell Chrome we want to load some potentially unsavory extensions. Navigate to chrome://extensions/ and toggle the developer mode switch.

Toggle the switch on the top right of the Extensions page.

This will present a new set of options below the header, one of which is “Load unpacked.” Select it and choose the folder for your repo. The Extensions page should now list your extension and it will be active if you check the extension bar (click the puzzle icon if it’s not showing by default).

Next up: showing it to the world 🚀

If everything works as expected, navigate to the folder containing your project and create a ZIP folder from it. You’ll use this in the next step.

How to publish on the Chrome Web Store

Walkthrough: Getting a Chrome Web Store developer account


  • a Google account
  • ZIP folder containing your extension files
  • $5 USD

Navigate to, and click the Gear icon to move to the Developer Dashboard.

You’ll be presented with an onboarding flow for registering as a Chrome Web Store Developer.

Complete this flow, and you’re now a Chrome Web Store Developer 🎉

At this point, you should already have a ZIP folder containing your project’s extension files.

The dashboard will show you your existing extensions and allow you to create a new one. Click “New Item” and, in the prompt, select your ZIP folder.

You’ll land on a page that allows you to edit all of the store-related fields for your extension. Only some of these may be required to submit your extension for review. To see which fields you still need to fill out, click the “Why can’t I submit?” button. You’ll see something like this:

Fill out the relevant fields for your extension, and the “Submit for review” button will be available. Submit your app, wait a few days for review, and then your extension will be live for the world 🎊

I used this process to create Passport, an extension to give you an inspiring New Tab Page. Available now for Chrome, Edge, Safari, and Firefox.



Michael Flores

Fan of tech, code, and coffee. Occasional starter of new things. Learn more: