Browser Extension Messaging

Dan Pastori

December 12nd, 2023

Blog post header image

One of the most confusing parts of developing your first browser extension is how to make each part communicate efficiently. Reading the docs doesn’t help. There’s ports and one time message calls, confusion on how to handle responses whether they are synchronous or asynchronous, and it’s super difficult to target certain parts of your extension.

That’s where the webext-bridge package comes in. The webext-bridge package allows you to easily communicate between different parts of your extension. Every piece is handled cleanly and efficiently. Most importantly, you can target where you are sending the message so you don’t have check if the part of the extension receiving the message should be receiving the message.

Let’s run though how to use the webext-bridge package.

Installing the webext-bridge package

First, we will need to add the webext-bridge package to our browser extension. To do that, run the following command:

Install the webext-bridge package

yarn add webext-bridge

That’s it! Now we can begin to use the package within our extension.

Including the right module

Let’s say we have 3 pieces to our extension. We have a background script, content script, and popup. Each piece of the extension needs to communicate with one another efficiently.

For the sake of simplicity in this example, we’ll say our popup script lives in the popup.js file, our background script in background.js, and our content script in content.js.

The most important part of using the webext-bridge package is to import the right module in the right place when setting up your communication. Let’s say we want to handle communication in the content script:

Handle communication from the content script

import { sendMessage, onMessage } from "webext-bridge/content-script"

Notice how we import the webext-bridge/content-script module? That module is scoped to the content script. So when we target a message to the content script, we ensure it’s going to the right place and getting picked up by the script itself.

The same goes for the popup and the background script. To handle communication in either of those areas, you’d add the following code respectively:

Handle communication from the popup

import { sendMessage, onMessage } from "webext-bridge/popup"

or

Handle communication from the background page

import { sendMessage, onMessage } from "webext-bridge/background"

Once you have the right module imported in your code, you are ready to pass messages!

Sending Messages

Now that we have our modules included, let’s send some messages! This can happen on a user interaction, a timed event, or anywhere within your extension you need to communicate.

If you notice, when you import a module, you are importing two methods, sendMessage() and onMessage(). Let’s look at the sendMessage() method first.

The sendMessage() method is, you guessed it, how you send a message. It accepts 3 parameters no matter where you include it:

  • messageId - ID of the message that we are sending. I usually set this to an uppercase enum or string value so it's easy to listen for and makes sense.
  • data - JSON data to send along with the message. Used for processing.
  • target - The target we are sending the message to. In our example, there are 3 targets we will be using: background, content-script, and popup. We will also show how to target the content script at a specific tab.

Let’s say we want to send a message from our popup to the background. Our full code would look like this:

Send message from popup to background

import { sendMessage, onMessage } from "webext-bridge/popup";

const response = await sendMessage("MESSAGE_ID", {
    // your data
}, "background");

The two big things to note are the MESSAGE_ID which will identify the message where we intend to receive it and handle the functionality, and the background target. The background target identifies the background script as the receiving end of the message.

Right now, we are halfway through the process. Let’s look at the onMessage() handler and finish up this message passing.

Receiving Messages

So we have a message being passed to our background script, but how do we handle it? That’s where the onMessage() handler comes in. The `

Want to work together?

Professional developers choose Server Side Up to ship quality applications without surrendering control. Explore our tools and resources or work directly with us.

Join our community

We're a community of 3,000+ members help each other level up our development skills.

Platinum Sponsors

Active Discord Members

We help each other through the challenges and share our knowledge when we learn something cool.

Stars on GitHub

Our community is active and growing.

Newsletter Subscribers

We send periodic updates what we're learning and what new tools are available. No spam. No BS.

Sign up for our newsletter

Be the first to know about our latest releases and product updates.

    Privacy first. No spam. No sharing. Just updates.