Skip to content

Extension Messaging

When implementing a Webfuse Extension you probably want the different components of your Extensions to be able to communicate with each other. We offer two different ways to enable this:

  1. In-Extension Messaging – Allows you to send messages between the different components of your Extension on a single participant’s side.
  2. Webfuse Broadcast Messaging – Allows you to broadcast messages to all participants which can then be received by the different components of your Extension.

Extension messages are a way to send messages between the different components of your Extension on a single participant’s side.

Sending a message from any component to Popup, Background, and Side Panel can be done by using runtime.sendMessage():

browser.runtime.sendMessage(message);

Sending a message from Popup, Background, Side Panel, and Newtab to the tab Content script (and Newtab pages) can be done by using tabs.sendMessage().

browser.tabs.sendMessage(tabId, message);
browser.runtime.onMessage.addListener((message) => {
if (message.command === 'sendMessageToTabs') {
browser.webfuseSession.getTabs().then((tabs) => {
sendMessageToTabs(tabs);
});
}
});
function sendMessageToTabs(tabs) {
tabs.forEach((tab) => {
browser.tabs.sendMessage(tab.id, {greeting: 'Hi from background'}).then((response) => {
console.log('response from tab', tab.id, response);
});
});
}

Here’s the corresponding content component script:

browser.runtime.onMessage.addListener((message, sender) => {
if (message.greeting === 'Hi from background') {
return ({ response: 'Hi from content script' });
}
});

Receiving a message in any component can be done by using runtime.onMessage.addListener():

browser.runtime.onMessage.addListener((message, sender) => {});

Both runtime.sendMessage() and tabs.sendMessage() return a Promise that resolves with the first listener’s response. Listeners can respond synchronously by returning a value, or asynchronously by returning a Promise.

// content.js — handling messages from background via tabs.sendMessage()
browser.runtime.onMessage.addListener((message, sender) => {
// Sync: return a value directly
if (message.type === 'GET_PAGE_DATA') {
return { title: document.title, url: window.location.href };
}
// Async: return a Promise — the messenger awaits it before responding
if (message.type === 'WAIT_FOR_ELEMENT') {
return new Promise((resolve) => {
const check = () => {
const el = document.querySelector(message.selector);
if (el) return resolve({ found: true, text: el.textContent });
setTimeout(check, 200);
};
check();
});
}
});
// background.js — calling the content script and awaiting the response
async function getPageData() {
const tabs = await browser.webfuseSession.getTabs();
const activeTab = tabs.find(t => t.active);
if (!activeTab) return;
const data = await browser.tabs.sendMessage(activeTab.id, { type: 'GET_PAGE_DATA' });
console.log('Page title:', data.title);
}

The same pattern works with runtime.sendMessage() for communication between content scripts, popups, side panels, and the background:

// background.js — handling messages from content script or popup
browser.runtime.onMessage.addListener((message, sender) => {
if (message.type === 'FETCH_DATA') {
return fetch(message.url).then(r => r.json());
}
});
// content.js or popup.js — sending a message to background and awaiting the response
const data = await browser.runtime.sendMessage({ type: 'FETCH_DATA', url: '/api/data' });
console.log('Received:', data);

In addition to messaging between components within an Extension, the Session API also allows you to broadcast a message to all participants within a Session. This is useful if you want to communicate with Extensions loaded on other participants’ side, want to communicate to pages that embed your space, interface with your Extension using the REST API.

browser.webfuseSession.broadcastMessage(message);

The Widget API also allows you to broadcast a message to all participants within a Session.

// Initialize Webfuse space and create a Session with event listeners
webfuse.initSpace('your_widget_key', 'your_space_id').then(async space => {
const session = space.session();
session.on('tab_relocate_start', (session, event) => {
session.broadcastMessage(`Navigating to a new page: ${event.url}`);
});
// Start the Session
await session.start();
});

Messages to the broadcast channel can also be sent using the REST API, allowing your backend to send messages to all participants in a Session.

send-message.py
import requests
API_Key = "<API_KEY>"
Session_ID = "<SESSION_ID>"
url = f"https://app.webfuse.io/v2/spaces/sessions/{Session_ID}/message/"
headers = {
"Authorization": f"Token {API_Key}",
"Content-Type": "application/json"
}
data = {
"message": {
"content": "Hello from REST API!"
}
}
response = requests.post(url, json=data, headers=headers)
print(response.json())

You can listen for broadcast messages by using browser.webfuseSession.on.addListener() to listen for broadcasted message and session events.

For example, if you want to listen for messages from the background script, you can do the following:

browser.webfuseSession.on.addListener((payload, sender) => {
// Case 1: Handle session events
// These objects always have an 'event_type' property (e.g., 'session_ended')
if (payload.event_type) {
if (payload.event_type === 'session_ended') {
console.log('Session ended at:', payload.final_location);
}
}
// Case 2: Handle broadcast messages
// These objects always have a 'message' property
if (payload.message) {
console.log('Broadcast received:', payload.message);
}
});

Receiving a Broadcast Using the Widget API

Section titled “Receiving a Broadcast Using the Widget API”

If you want to listen for messages using the Widget API, you can use session.on('message') to listen for message events.

webfuse.initSpace('your_widget_key', 'your_space_id').then(async space => {
const session = space.session();
session.on('message', (session, event) => {
console.log("Received message:", event.data.message, "from", event.origin);
});
// Start the Session
await session.start();
});