Search code examples
iframegoogle-chrome-extension

Do Chrome extensions access iframes?


if I write a Chrome extension that runs a snippet of JS on a page, will it also run in any iframes I create? If so, does this apply for iframes created by Javascript after the DOM has loaded?

Thanks!


Solution

  • Yes, a Chrome Extension content script can run in all iframes if you specify "all_frames": true in manifest.json, https://developer.chrome.com/docs/extensions/reference/manifest/content-scripts:

    {
      "name": "My extension",
      ...
      "content_scripts": [
        {
          "matches": ["*://www.google.com/*"],
          "css": ["mystyles.css"],
          "js": ["jquery.js", "myscript.js"],
          "all_frames": true
        }
      ],
      ...
    }
    

    These scripts will run in each matching iframe as separate instances i.e. the script running in an iframe can't directly access variables of the parent script. You can check whether the instance runs inside an iframe: if (window !== top) { console.log('in iframe') }.

    The about:blank iframes

    The above example matches only those iframes that contain a www.google.com inside them, but sometimes you may want to run your content scripts in the so-called about:blank iframes (their internal location.href is "about:blank") either without src or a src like "about:blank" or "about:srcdoc".

              "all_frames": true,
              "match_about_blank": true,
              "match_origin_as_fallback": true
    

    Alternatively, you can just access their content directly via iframeElement.contentDocument or iframeElement.contentWindow from your content script running in the main document as such iframes are same-origin. Note that running an instance of a content script consumes some resources (time, CPU, and memory), which becomes a problem for users with many tabs open.

    Caveats:

    • Currently Chrome can't run content scripts in iframes with javascript: URL in src.

    • src attribute only tells you the initial URL of the iframe, but you can't trust it as the iframe may have been navigated inside and thus become cross-origin, in which case accessing its actual contents will throw an exception. The solution is either to do it inside try{}catch(e){} or check the availability of URL getter to avoid triggering an exception:

      let ok;
      try {
        ok = !!Object.getOwnPropertyDescriptor(elem.contentWindow.location, 'href').get;
      } catch (e) { /* Chrome 85 and older throws in sandboxed frames */ }
      if (ok) {
        console.log(elem.contentDocument);
      }