Join MDN and developers like you at Mozilla's View Source conference, November 2-4 in Portland, Oregon. Learn more at

Cross Process Object Wrappers

This document describes Cross Process Object Wrappers (CPOWs), which enable chrome code to synchronously access content in multiprocess Firefox.

In multiprocess Firefox, chrome code runs in a different process from web content. So chrome code can't directly interact with web content: instead, it must factor out the code that interacts with web content into separate scripts that are called frame scripts.

Chrome code can load frame scripts into the content process using the message manager, and can then communicate with them using a message-passing API. To learn more about this, see the documentation on using the message manager.

Chrome to content messaging must be asynchronous. This is because the chrome process runs the Firefox UI, so if it were blocked by the content process, then a slow content process could cause Firefox to become unresponsive to users.

Converting synchronous code to be asynchronous can be difficult and time-consuming. As a migration aid, the messaging framework enables frame scripts to make content objects available to chrome through a wrapper called a Cross Process Object Wrapper, also known as a CPOW. However, although CPOWs are convenient, they have serious limitations and can cause responsiveness problems, so should only be used when necessary and only as a migration aid.

Passing CPOWs from frame scripts

Frame scripts can send messages to chrome using one of two global functions: sendAsyncMessage() or sendSyncMessage(). The optional third parameter to each of these functions is an object whose properties are objects to wrap. For example, this frame script sends a DOM node to chrome when the user clicks it, as the clicked property of the third argument:

// frame script
addEventListener("click", function (event) {
  sendAsyncMessage("my-e10s-extension-message", {}, { clicked : });
}, false);

In the chrome script, the DOM node is now accessible through a Cross Process Object Wrapper, as a property of the objects property of the message. The chrome script can get and set the wrapped object's properties and call its functions:

// chrome script
windowMM.addMessageListener("my-e10s-extension-message", handleMessage);

function handleMessage(message) {
  let wrapper = message.objects.clicked;
  wrapper.innerHTML = "<h2>Modified by chrome!</h2>"
  wrapper.setAttribute("align", "center");

Auto-generated CPOWs

Add-ons that have not declared themselves multiprocess compatible are set up with a number of compatibility shims. One of these shims provides the following behavior: whenever chrome code tries to access content directly (for example, through window.content or browser.contentDocument), it is given back a CPOW that wraps the content object. This means that examples like this will actually work, even in multiprocess Firefox:

gBrowser.selectedBrowser.contentDocument.body.innerHTML = "replaced by chrome code";

It's still important to keep in mind, though, that this is access through a CPOW and not direct access to content.

Bidirectional CPOWs

A common pattern is for chrome code to access content objects and add event listeners to them. To deal with this, CPOWs are bidirectional. This means that if content passes a CPOW to the chrome process, the chrome process can synchronously pass objects (such as event listener functions) into functions defined in the CPOW.

This means you can write code like this:

// frame script

On mouseover, send the button to the chrome script as a CPOW.

var button = content.document.getElementById("click-me");

button.addEventListener("mouseover", function (event) {
  sendAsyncMessage("my-addon-message", {}, { element : });
}, false);
// chrome script

Load the frame script, then listen for the message.
When we get the message, extract the CPOW and add
a function as a listener to the button's "click" event.

  browserMM.loadFrameScript("chrome://my-addon/content/frame-script.js", false);
  browserMM.addMessageListener("my-addon-message", function(message) {
    let wrapper = message.objects.element;
    wrapper.addEventListener("click", function() {
      console.log("they clicked");

Mapping content documents to XUL browsers

A common pattern is to get the XUL <browser> that corresponds to a content document. To enable this, gBrowser.getBrowserForDocument and gBrowser.getBrowserForContentWindow can be passed a CPOW for the content document and content window, respectively, and return the XUL  <browser> that these documents / windows belong to. Both return null if no such browser can be found.

Limitations of CPOWs

Although CPOWs can be convenient they have several major limitations, which are listed below.

CPOWs and platform APIs

You can't pass CPOWs into platform APIs that expect to receive DOM objects. For example, you can't pass a CPOW into nsIFocusManager.setFocus().

Chrome responsiveness

The lack of an synchronous API in the chrome side is intentional: because the chrome process runs the Firefox UI, any responsiveness problems affect the whole browser. By making the chrome process block on the content process, CPOWs break this principle and allow an unresponsive content process to make the whole browser unresponsive.


Although the wrapper looks just like an object completely contained in the chrome script scope, it's really just a reference to an object in the content process. When you access a property of the wrapper, it sends a synchronous message to the content process and returns the result. This means it is many times slower to use than an object.

Message ordering

CPOWs can violate assumptions you might make about message ordering. Consider this code:

mm.addMessageListener("GotLoadEvent", function (msg) {
  mm.sendAsyncMessage("ChangeDocumentURI", {newURI: ""});
  let uri = msg.objects.document.documentURI;
  dump("Received load event: " + uri + "\n");

This sends a message asking the frame script to change the current document URI, then accesses the current document URI via a CPOW. You might expect the value of uri to come back as "". But it might not: in order to avoid deadlocks, CPOW messages can bypass normal messages and be processed first. It’s possible that the request for the documentURI property will be processed before the "ChangeDocumentURI" message, in which case uri will have its previous value.

For this reason, it’s best not to mix CPOWs with normal message manager messages. It’s also a bad idea to use CPOWs for anything security-related, since you may get results that are not consistent with surrounding code that might use the message manager.

Document Tags and Contributors

Contributors to this page: wbamberg, evilpie, billmccloskey
Last updated by: wbamberg,