Message passing

Messaging APIs allow you to communicate between different scripts running in contexts associated with your extension. This includes communication between your service worker, chrome-extension://pages and content scripts. For example, an RSS reader extension might use content scripts to detect the presence of an RSS feed on a page, then notify the service worker to update the action icon for that page.

There are two message passing APIs: one for one-time requests, and a more complex one for long-lived connections that allow multiple messages to be sent.

For information about sending messages between extensions, see the cross-extension messages section.

One-time requests

To send a single message to another part of your extension, and optionally get a response, call runtime.sendMessage() or tabs.sendMessage(). These methods let you send a one-time JSON-serializable message from a content script to the extension, or from the extension to a content script. Both APIs return a Promise which resolves to the response provided by a recipient.

Sending a request from a content script looks like this:

content-script.js:

(async () => {
  const response = await chrome.runtime.sendMessage({greeting: "hello"});
  // do something with response here, not outside the function
  console.log(response);
})();

Responses

To listen for a message, use the chrome.runtime.onMessage event:

// Event listener
function handleMessages(message, sender, sendResponse) {
  if (message !== 'get-status') return;

  fetch('https://example.com')
    .then((response) => sendResponse({statusCode: response.status}))

  // Since `fetch` is asynchronous, must return an explicit `true`
  return true;
}

chrome.runtime.onMessage.addListener(handleMessages);

// From the sender's context...
const {statusCode} = await chrome.runtime.sendMessage('get-status');

When the event listener is called, a sendResponse function is passed as the third parameter. This is a function that can be called to provide a response. By default, the sendResponse callback must be called synchronously.

If you call sendResponse without any parameters, null is sent as a response.

To send a response asynchronously, you have two options: returning true or returning a promise.

Return true

To respond asynchronously using sendResponse(), return a literal true (not just a truthy value) from the event listener. Doing so will keep the message channel open to the other end until sendResponse is called, allowing you to call it later.

Return a promise

From Chrome 148, you can return a promise from a message listener to respond asynchronously. This update is rolling out gradually, so you may find that it's not yet available in all users' browsers. You should make sure your extension can handle whether this capability is enabled or not. Using return true; will continue to work for asynchronous responses whether this capability is enabled or not.

If the promise resolves, its resolved value is sent as the response.

If the promise is rejected, the sender's sendMessage() call will be rejected with the error's message. See the error handling section for more details and examples.

An example that shows returning a promise that could resolve or reject:

// Event listener
function handleMessages(message, sender, sendResponse) {
  // Return a promise that wraps fetch
  // If the response is OK, resolve with the status. If it's not OK then reject
  // with the network error that prevents the fetch from completing.
  return new Promise((resolve, reject) => {
    fetch('https://example.com')
      .then(response => {
        if (!response.ok) {
          reject(response);
        } else {
          resolve(response.status);
        }
      })
      .catch(error => {
        reject(error);
      });
  });
}
chrome.runtime.onMessage.addListener(handleMessages);

You can also declare a listener as async to return a promise:

chrome.runtime.onMessage.addListener(async function(message, sender) {
  const response = await fetch('https://example.com');
  if (!response.ok) {
    // rejects the promise returned by `async function`.
    throw new Error(`Fetch failed: ${response.status}`);
  }
  // resolves the promise returned by `async function`.
  return