Time to read: 8 minutes

I’ve been researching (and acquiring) chrome extensions for a few months now.

The general thesis is:

  • user base is easy to grow via 1 click install
  • value is easy to track (do users use product daily, weekly, etc)
  • are those who do use a lot willing to pay some small number (<$10/month)?

I specifically am looking for extensions where the developer has stopped adding updates and users are starting to complain. I’ve found these popular extensions usually are written in a developers spare time, or when he/she is learning to code, and are no longer interesting to them.

However, they are super interesting to me. A lot have 50,000 users or more. If you do some simple back of the napkin math, it is not impossible to estimate a 1% purchase rate (maybe over the course of 6 months of adding value and marketing) at $5/month.

This equates to $2,500 in MRR. Not much, but a start. Especially when the users are begging for updates and are not getting any!

I’ve also found most developers do a poor job aligning the value metric for their extensions (for the ones that are paid).

They might have a VPN service that asks you to upgrade if you’re trying to connect more devices (in theory, this might work, but I’d rather charge someone when they’ve used the service a lot, not when trying to get set up on their iphone, ipad and mac + their spouses devices)

If anything, getting the entire family set up should lead to free credits (aka product will be more sticky).

So I think there is some interesting angles to be taken on growing the extension by aligning the value to what the customer is looking for.

Another benefit (thanks to Julian Shapiro from Bell Curve for discussing) is how much easier it is to grow a user base with the 1 click chrome extension install!

You can build a small subsection of your web app into the extension, and when a user needs to upgrade, have them do so through your web app! Bam, you’ve tackled two birds with 1 stone.

  • Didn’t have 100,000 users hitting your database servers from day 1
  • Deal with scaling challenges only once you start to make $

Working with extensions are surprisingly approachable too. Most developers know Javascript. Or have some working familiarity with it. While monolith web apps can be incredibly complex extensions rarely are. Going back to, most popular ones, are written for fun as side projects.

I am not a very good developer. I don’t follow convention (problems with being self taught) and although I can contribute in a few different languages, I shouldn’t be writing large scale apps from scratch.

Extensions though, usually only have 3-4 files (background.js, mainfest.json, index.html, content.js + sometimes have a style.css)

A lot are not even minified! So this means, you can inspect easily, see the quality of the code and think about extending the functionality for your Pro version down the road.

(don’t be that guy who copies and pastes the code and re-releases. Buy the extension from the developer)

In this model, it is not hard to estimate what each file does, there are not 17 layers of syntactical complexity and you might not even have to interface with a server. Some extensions have all of the logic client side where you can see it!

The background.js file runs in the background of the chrome browser. Wow, that was difficult to understand I know!

The manifest.json is very similar to a package.json in node. Set up docs for the project.

The index.html + styles.css are exactly what you’d think they are. A lot of extensions stop here! Some don’t even have a content.js or other JS files.

But for the ones that do, the content.js can easily be understood:

content.js interacts with the pages your chrome browser is viewing.

You’ll want to pay attention to scopes, and see where each script can access via it’s scope. But that is pretty much all there is.

Want to write a script that does stuff in the background every time chrome is opened? Ok, you don’t need a content.js file!


You can easily start your project with the following structure

  • project-name/
    • background.js
    • mainfest.json
    • index.html
    • styles.css

And that is all you need (the index and styles are not even needed).

Your mainfest.json should look like this:

  "name": "Private History",
  "version": "1.0",
  "description": "Private History: Protection Even When You Don't Need It :)",
  "manifest_version": 2,
  "incognito": "split",
  "background": {
  "scripts": ["background.js"]
  "permissions": [
"icons": {
    "128": "icon.png"

This is (most of) the manifest.json of an extension I am releasing soon. Lets walk through what each line does, add some clarity because it took me awhile to understand, and you’ll be up to speed in no time.

The name is pretty self-explanatory. Here Private History is the title of our extension.

Version is whatever you’d like it to be. Since this is our first major release, I’ve chosen 1.0.0

Description tells you what the extension does. For Private History, we encrypt and protect your Internet traffic. Think a VPN that stops both local tracking and online tracking.

If you’re interested in private history you can click here => https://kameronkales.com/privatehistory to join the early access list.

Manifest_version is 2. Just go with this. Its how Google decides to load your files. Don’t change this or everything will break.

Incognito is set to split, so that if the user wants the extension to run in incognito, it will do so in its own split process.

Background here is set to scripts: [“background.js”].

This just routes to where our background.js file is inside of our project and enables it to run.

Permissions are set to history because in this instance we want to be able to alter the users history. For Private History we will be password protecting and removing + stopping other sites from tracking you.

The last item in our manifest is the icon we show to the user in their chrome browser. This is simple, just use an online service to convert an image to the right size and be done!

Bam. That is it. Now you have a working manifest.json.

Write some basic javascript in your background.js and load the folder into chrome (you’ll need to turn on developer mode) by pasting this into your browser:


Developer mode will be a toggle in the top right corner. Once you do that, you can load an unpacked extension in the top left, and be off to the races!

If you wrote something basic like

console.log("Hello from the background.js file") 

you should be able to open “Inspect View” => background page and see the information displayed in the console!

Congrats, you’ve now written your first extension!

That was not bad.

There are some other hurdles to tackle. For example, in our extension we make an auth call to an api (set up on api gateway + lambda). We do this in vanilla JS because I can, but others might want to use an easier library. To do so, you’ll need to download the files and zip them up in your extension.

Here is the code we use, to make this vanilla call digest-able. Thanks to stackoverflow for the help :)

var HttpClient = function() {
    this.get = function(aUrl, aCallback) {
        var anHttpRequest = new XMLHttpRequest();
        anHttpRequest.onreadystatechange = function() { 
            if (anHttpRequest.readyState == 4 && anHttpRequest.status == 200)

        anHttpRequest.open( "GET", aUrl, true );            
        anHttpRequest.send( null );
   this.post = function(aUrl, data, aCallback) {
        var anHttpRequest = new XMLHttpRequest();
        anHttpRequest.onreadystatechange = function() { 
            if (anHttpRequest.readyState == 4 && anHttpRequest.status == 200)

        anHttpRequest.open( "POST", aUrl, true ); 
        anHttpRequest.setRequestHeader("Content-Type", "application/json");
        formatted_data = JSON.stringify(data)
        anHttpRequest.send( formatted_data );

Then, when we want to make a request, we do:

var client = new HttpClient();
    var api = 'http://localhost:3000/api'
    client.post(api, urls, function(response) {
        ..business logic here

You’d swap your api out for either your correct port/route or a production one, but with this, you get the drift :)

If you got this far, you’re well on your way to deploying your first extension. A WAY easier milestone than an entire web app that you’re not sure will even get customers :)

Alright. That is it for this post. If you’re interested in private history you can click here => https://kameronkales.com/privatehistory to join the early access list.

I will come back and add more as I go. Hopefully you found it interesting and helpful!