docs.rodeo

MDN Web Docs mirror

runtime.onMessage

{{AddonSidebar}} 

Use this event to listen for messages from another part of your extension.

Some example use cases are:

To send a message that is received by the onMessage() listener, use {{WebExtAPIRef("runtime.sendMessage()")}}  or (to send a message to a content script) {{WebExtAPIRef("tabs.sendMessage()")}} .

[!NOTE] Avoid creating multiple onMessage() listeners for the same type of message because the order in which multiple listeners fire is not guaranteed.

If you want to guarantee the delivery of a message to a specific endpoint, use the connection-based approach to exchange messages.

Along with the message itself, the listener is passed:

You can send a synchronous response to the message by calling the sendResponse() function inside your listener. See the sending a synchronous response example.

To send an asynchronous response, there are two options:

[!NOTE] You can also use a connection-based approach to exchange messages.

Syntax

browser.runtime.onMessage.addListener(listener)
browser.runtime.onMessage.removeListener(listener)
browser.runtime.onMessage.hasListener(listener)

Events have three functions:

addListener syntax

Parameters

Examples

Simple example

This content script listens for click events on the web page. If the click is on a link, it messages the background page with the target URL:

// content-script.js

window.addEventListener("click", notifyExtension);

function notifyExtension(e) {
  if (e.target.tagName !== "A") {
    return;
  }
  browser.runtime.sendMessage({ url: e.target.href });
}

The background script listens for these messages and displays a notification using the notifications API:

// background-script.js

browser.runtime.onMessage.addListener(notify);

function notify(message) {
  browser.notifications.create({
    type: "basic",
    iconUrl: browser.extension.getURL("link.png"),
    title: "You clicked a link!",
    message: message.url,
  });
}

Sending a synchronous response

This content script sends a message to the background script when the user clicks on the page. It also logs any response sent by the background script:

// content-script.js

function handleResponse(message) {
  console.log(`background script sent a response: ${message.response}`);
}

function handleError(error) {
  console.log(`Error: ${error}`);
}

function sendMessage(e) {
  const sending = browser.runtime.sendMessage({
    content: "message from the content script",
  });
  sending.then(handleResponse, handleError);
}

window.addEventListener("click", sendMessage);

Here is a version of the corresponding background script that sends a response synchronously from inside the listener:

// background-script.js

function handleMessage(request, sender, sendResponse) {
  console.log(`content script sent a message: ${request.content}`);
  sendResponse({ response: "response from background script" });
}

browser.runtime.onMessage.addListener(handleMessage);

And here is another version that uses {{jsxref("Promise.resolve()")}} :

// background-script.js

function handleMessage(request, sender, sendResponse) {
  console.log(`content script sent a message: ${request.content}`);
  return Promise.resolve({ response: "response from background script" });
}

browser.runtime.onMessage.addListener(handleMessage);

Sending an asynchronous response using sendResponse

Here is an alternative version of the background script from the previous example. It sends a response asynchronously after the listener returns. Note return true; in the listener: this tells the browser that you intend to use the sendResponse argument after the listener returns.

// background-script.js

function handleMessage(request, sender, sendResponse) {
  console.log(`content script sent a message: ${request.content}`);
  setTimeout(() => {
    sendResponse({ response: "async response from background script" });
  }, 1000);
  return true;
}

browser.runtime.onMessage.addListener(handleMessage);

[!WARNING] Do not prepend async to the function. Prepending async changes the meaning to sending an asynchronous response using a promise, which is effectively the same as sendResponse(true).

Sending an asynchronous response using a Promise

[!NOTE] Promise as a return value is not supported in Chrome until Chrome bug 1185241 is resolved. As an alternative, return true and use sendResponse.

This content script gets the first <a> link on the page and sends a message asking if the link’s location is bookmarked. It expects to get a Boolean response (true if the location is bookmarked, false otherwise):

// content-script.js

const firstLink = document.querySelector("a");

function handleResponse(isBookmarked) {
  if (isBookmarked) {
    firstLink.classList.add("bookmarked");
  }
}

browser.runtime
  .sendMessage({
    url: firstLink.href,
  })
  .then(handleResponse);

Here is the background script. It uses ``{{WebExtAPIRef(“bookmarks.search()”)}}&nbsp; to see if the link is bookmarked, which returns a {{jsxref("Promise")}} :

// background-script.js

function isBookmarked(message, sender, response) {
  return browser.bookmarks
    .search({
      url: message.url,
    })
    .then((results) => results.length > 0);
}

browser.runtime.onMessage.addListener(isBookmarked);

If the asynchronous handler doesn’t return a Promise, you can explicitly construct a promise. This rather contrived example sends a response after a 1-second delay, using {{domxref("Window.setTimeout", "setTimeout()")}} :

// background-script.js

function handleMessage(request, sender, sendResponse) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ response: "async response from background script" });
    }, 1000);
  });
}

browser.runtime.onMessage.addListener(handleMessage);

{{WebExtExamples}} 

Browser compatibility

{{Compat}} 

[!NOTE] This API is based on Chromium’s chrome.runtime API. This documentation is derived from runtime.json in the Chromium code.

In this article

View on MDN