Chrome extension MV2 access to page data

Chrome extensions exist in an “isolated world” to prevent global var collisions between the website and the extension that runs on a given website. This mostly applies to content_scripts in an extension.

E.g. window.foo: my extension declares foo in the global scope and the website the extension runs on also declares foo in the global scope. With “isolated world” scoping for the extension, this is not a worry since it doesn’t share scope with the web page it runs on.

What about when the extension needs to access the global vars of the page it runs on? Then you run into a problem since the extension is scoped into an “isolated world”. But content_scripts in the extension do have access to the web page’s DOM. The work around is to inject a DOM element that will expose the global vars needed:

// content_scripts.js

// Create a DOM element to hold the global vars as JSON
const elTarget = document.createElement('script');
elTarget.setAttribute('id', 'content-script-global-target');
elTarget.setAttribute('type', 'application/json');
document.body.appendChild(elTarget);

// Create a DOM script to expose and populate the global vars
const elExpose = document.createElement('script');
elExpose.setAttribute('id', 'content-script-global-expose');
elExpose.appendChild(document.createTextNode(`
  (function() {
    const elJson = document.querySelector('#content-script-global-target');
    elJson.innerText = JSON.stringify({
      boo: window.boo,
      far: window.far,
    });
  })();
`);
document.body.appendChild(elExpose);

Now any scripts in the extension that needs access to the web page variables can read them from the DOM JSON:

const pageGlobals = JSON.parse(
  document.querySelector('#content-script-global-target').innerText
);

⚠️ It’s worth noting that this only works with Chrome extension manifest version 2 (MV2). The new version (MV3) adds a Content Security Policy that prevents inline scripts from executing on the page. Unfortunately there is no known workaround that I could find except to have the hosted web page expose the DOM JSON.

Links