Join MDN and developers like you at Mozilla's View Source conference, 12-14 September in Berlin, Germany. Learn more at

Cross-domain Content Scripts

By default, content scripts don't have any cross-domain privileges. In particular, they can't:

However, you can enable these features for specific domains by adding them to your add-on's package.json under the "cross-domain-content" key, which itself lives under the "permissions" key:

"permissions": {
    "cross-domain-content": ["", ""]
  • The domains listed must include the scheme and fully qualified domain name, and these must exactly match the domains serving the content - so in the example above, the content script will not be allowed to access content served from
  • Wildcards are not allowed.
  • This feature is currently only available for content scripts, not for page scripts included in HTML files shipped with your add-on.

Cross-domain iframes

The following "main.js" creates a page-worker which loads a local HTML file called "page.html", attaches a content script called "page.js" to the page, waits for messages from the script, and logs the payload.

var data = require("sdk/self").data;

var pageWorker = require("sdk/page-worker").Page({
  contentURL: data.url("page.html"),
  contentScriptFile: data.url("page-script.js")

pageWorker.on("message", function(message) {

The "page.html" file embeds an iframe whose content is served from "":

    <!DOCTYPE html>
    <!-- page.html -->
        <iframe id="wikipedia" src=""></iframe>

The "page-script.js" file locates "Today's Featured Article" and sends its content to "main.js":

// page-script.js
var iframe = window.document.getElementById("wikipedia");
var todaysFeaturedArticle = iframe.contentWindow.document.getElementById("mp-tfa");

For this to work, we need to add the "cross-domain-content" key to "package.json":

"permissions": {
  "cross-domain-content": [""]

The add-on should successfully retrieve the iframe's content.

Cross-domain XMLHttpRequest

The following add-on creates a panel whose content is the summary weather forecast for Shetland. If you want to try it out, you'll need to register and get an API key.

The "main.js":

  • creates a panel whose content is supplied by "panel.html" and adds a content script "panel-script.js" to it
  • sends the panel a "show" message when it is shown
  • adds a button which shows the panel when it is clicked
// main.js
var data = require("sdk/self").data;

var forecast_panel = require("sdk/panel").Panel({
  height: 50,
  contentURL: data.url("panel.html"),
  contentScriptFile: data.url("panel-script.js")

forecast_panel.on("show", function(){

  id: "get-forecast",
  label: "Get the forecast",
  icon: "./icon-16.png",
  onClick: function() {;

The "panel.html" just includes a <div> block for the forecast:

<!DOCTYPE html>
<!-- panel.html -->

    <div id="forecast_summary"></div>

The "panel-script.js" uses XMLHttpRequest to fetch the latest forecast:

// panel-script.js

var url = "";

self.port.on("show", function () {
  var request = new XMLHttpRequest();"GET", url, true);
  request.onload = function () {
    var jsonResponse = JSON.parse(request.responseText);
    var summary = getSummary(jsonResponse);
    var element = document.getElementById("forecast_summary");
    element.textContent = summary;

function getSummary(forecast) {
  return forecast.RegionalFcst.FcstPeriods.Period[0].Paragraph[0].$;

Finally, we need to add the "cross-domain-content" key to "package.json":

"permissions": {
  "cross-domain-content": [""]

Content Permissions and unsafeWindow

If you use "cross-domain-content", then JavaScript values in content scripts will not be available from pages. Suppose your content script includes a line like:

// content-script.js:
unsafeWindow.myCustomAPI = function () {};

If you have included the "cross-domain-content" key, when the page script tries to access myCustomAPI this will result in a "permission denied" exception.

Document Tags and Contributors

 Contributors to this page: wbamberg, Brettz9, erxin, evold
 Last updated by: wbamberg,