Well, this wasn't born as a blog post at first, but, I wanted to let the world now that I was able to build a Chrome extension! (I didn't publish it, tho)
TL;DR: Here's the GitHub repo: https://github.com/KevLehman/visible-ads
Requirements!
- VSCode (or similar editor)
- Git (to upload your project, or to clone the finished one!)
- An icon for your app (you can use this site to convert your image file to an icon)
- Patience ;)
Let's start!
We will create an extension to highlight (with a border) Google ads on the search results page (so they are identifiable by anyone!). We can do that by hand, but, we are developers, so, let's make an extension for it!
Let's start by creating a folder that will hold our extension's brain. I'll name it visible-ads
(you can name it whatever you want it).
Now that you have the folder, cd
into it and create a manifest.json
file (every chrome extension should have this file since this is the presentation card for them). Let's create them and open it into your editor of choice.
On that file, we will add the following information (for now):
With that, we're telling Chrome our extension's information. We'll add more information here as we write our extension.
Now, let's create our first JS file. We'll name it background.js
. This file will contain some logic that will run in the background when our extension starts. As before, here's the content and we'll talk about it after:
Let's see some details of it:
- First of all, we are using a global variable provided to all extensions:
chrome
. This global contains an API that allows us to interact with the browser. Elements such asstorage
orruntime
are only available through this variable. - We are using
chrome.runtime.onInstalled
API to add an event listener. This event will be fired when our extension is installed on a browser. - On the callback for that function, we'll use another browser API which allows us to interact with the browser storage. We'll add there a variable called
hide
that we'll use to modify our script's behavior. - The other API we're using is the
declarativeContent
API. This API allows our extension to decide on which domains our extension will work. For now, we'll limit it to run only ongoogle.com
. To read more about this API, you can see this link
How does the browser know this file should be run in the background? manifest.json
to the rescue! Add the following lines to your manifest.json
file:
Per Google's Developer Docs, to use the declarativeContent
or storage
APIs, we should request
them. Let's do this by setting up which permissions our extension needs. Where can we do this? In the manifest.json
file!. Go ahead to it again, and add the following lines:
(Note: for simplicity, we're adding the activeTab
permission here, but we'll use it later)
Now, let's start building our application logic!
Extension's Landing page (well, not really)
Our extension needs something a user can see and interact with! So, let's create a new file called action.html
(no CSS, I promise) and let's add some code to it:
This file will produce something like this (so you know how ugly it is):
Let's add some lines to manifest.json
file so the browser knows this is our "landing page" (well, a popup is what it'll be):
- We are using the same config to set the default title & icon for the page, as well as the popup that will show every time a user clicks on the icon (on chrome's extensions zone)
As you may notice, we are including a script
called action.js
, but we haven't done it yet! So let's create it! Create a file called action.js
. This part will be the main point of interaction between our extension and the Tab's DOM.
At the first line, we'll call document.addEventListener('DOMContentLoaded...
to make sure our script only runs when everything's ready (to avoid some undefined
s there, ugh). Let's see the first half of the file's content:
- We are getting the button that we created on our HTML file and the status
span
item we created. - Using the
storage
API, we retrieve the value for thehide
variable we defined there. We don't care for this to be synchronous, so let it be. - After getting the value from
hide
, we're using it to dynamically set the value of thestatus
label toactive
orinactive
. This won't be called every time we click, but every time we click on our extension's icon.
The second part of the file is this:
- We added an
onclick
listener to our button, which will perform the real work! - Inside this, the handler is updating the value saved on
storage
to be the inverse of the one there's now (effectively, toggling it). - On the callback for this
storage
call, let's update thestatus
label again. - After that, we'll use a new Chrome API to interact with the browser. This is the
tabs
API, which allows us to query the browser to get the tabs we want to use. For example, we could query only foractive
tabs by runningchrome.tabs.query({ active: true }, ...)
. For now, instead of querying it, we are using its handy function to get the tab we're on. As every other API used, this is asynchronous, so the work should be done on the callback - There, let's use another function that will allow us to communicate with something called
content
scripts. A content script is a file running on the context of web pages, allowing it to interact with the DOM of the tab we want. From the files we have, we are only allowed to interact with our extension's generated DOM (the HTML file we created above). - We're passing the command our content script will run as a message, and the value for
shouldToggle
. - On the callback (after the message has been received & processed), let's log the result value. In the real world, you will perform other things here, but, since this is a blog post, a
console.log
will suffice.
WAIT A MINUTE! We don't have any content script!!!
Keep calm. Let's create one! Create the content.js
file and add the following code:
- Our function
addStyles
will create a new CSS class within the tab's DOM with the border we want to add. - Our function
showAdBorder
will map over every ad (by the time of this blog post being written, ads contained theads-ad
class) and add the style we've created - The
removeAdBorder
will do the same, but removing the class instead - Another chrome API used:
runtime.onMessage
allows the tab to listen to whatever message we're passing to it. We pass messages as seen before by callingchrome.tabs.sendMessage
. - Here, if the command received is
init
(better naming the next time...) we'll callshowAdBorder
andremoveAdBorder
otherwise. - After finished, the function sends the response back to the emitter by calling
sendResponse
function. In case of failures, you can use this to emit errors too!
Now we have our content
script! Wooo! Yay! But, wait, again, how does the browser know that this is a content script? Let's go again to manifest.json
file and add the following lines:
Now we have a working extension! Woo!
Now, let's add one last thing. We really want this behavior to be enabled by default, isn't it? So, let's do that by setting up an onload
event listener on our content.js
file! Add the following lines:
Save all the files (in case you haven't done it yet), because we're going to upload our extension!
- Find your way to
chrome://extensions
on your browser. Make sure you have developer mode enabled on your extensions page! - Click on
Load Unpacked
button, and locate the folder you were working on (in my case, it was on~/Documents/visible-ads
- Wait for a second until it loads. If everything is OK, you should see something like this on your dashboard:
- If you are able to see it, it means it's running!
Let's try it. Go to www.google.com
, and look for something that will contain ads, like, basecamp
or amazon
As you can see, there's an ad. How do we know it is an ad? By the blue border around it. Now, you can share this extension with others so they don't confuse ads with organic results anymore!
Let's finish our extension with something we should've done at the very first. From a terminal, run git init
git add .
and git commit -m "your message goes here"
so your project is safe & you can modify it freely. For example, you can change the styles
variable to add a background color like the ones ads had on the past.
Thanks for reading! Happy coding!
Top comments (3)
Thanks for sharing your knowledge. This is a good starting point for the development of my first chrome extension. :-)
Hey I tried uploading the unpacked version but it doesn't appear to be working anymore? The ads aren't getting highlighted.
Also, how do you write the code so that the extension will run automatically, and doesn't require a toggle. (i.e. if the extension is on, it will run when you get to a new webpage). Thanks!
Thanks man for sharing this! Got the exact thing I was looking for to start!❤