Modify a web page before displaying it (WebExtensions)

How can I modify a web page before it’s displayed with WebExtensions? The canonical ways to modify a page are documented here:
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Modify_a_web_page

However, doing the way the page above suggested modifies the page after it has been displayed.

For instance, if I want to hide a certain element in a page:

  • I write the extension as above, then I click on a link and it loads and displays the page, but the element shows up visible for a very brief moment before it is finally hidden.

What I’m looking for:

  • A way to intercept the response from the server and modify the DOM before we display the page, so that the element is never visible to the user, not even for a millisecond.

I know this might increase the page load time, but my concern is to never have a certain element visible, even if the compromise is to have it take a few more seconds before the page is displayed. How can I achieve that using WebExtensions?

If you include a content script or style in the manifest and have it run at document_start, it should be applied before the first paint, and thus meet your criteria.

If you are not only concerned about visibility but need to remove page APIs, e.g. you want to prevent popups by removing all website access to the window.open function, then that is not reliably possible.

Hey @NilkasG, thanks for replying. Interesting, I missed that parameter the first time I read the manifest.json documentation. However, it still doesn’t seem to be working!

By introducing the "run_at": "document_start" in the appropriate content script in my manifest.json, here’s what happens:

  • The element doesn’t go away at all! It stays visible at all times. If I go to about:debugging and click Reload on my add-on, then go back to the page, the element is then gone, but if I refresh the page, or go to another video, it is visible once again. The only way to get it to hide the element is to go in about:debugging and reload the add-on, and even then it’ll only work once! If I refresh the page, or click another link (where the script should work), it just doesn’t.

This doesn’t happen if I remove the "run_at": "document_start", then it works as intended, removing the element every time, even if I refresh the page or go to another link (but there’s still the noticeable delay I’m trying to get rid of). Maybe I’m doing something wrong? Here’s my manifest.json:

{
  "author": "Jillboy",
  "content_scripts": [
    {
      "matches": ["*://*.youtube.com/watch?v=*"],
      "js": ["script.js"],
      "run_at": "document_start"
    }
  ],
  "description": "...",
  "manifest_version": 2,
  "name": "...",
  "version": "0.1"
}

And my script.js:

var sidebar = document.getElementById('watch7-sidebar');
sidebar.style.display = 'none';

It should work, right? By removing the "run_at": "document_start", it works fine. Why does that line suddenly break everything? I’ve been trying all day to get it to work with no success.

If you run scripts at document_start, they run before any elements, including the head and body, are created. In your script, the sidebar will thus be null.

You can, however, apply CSS that hides elements that don’t exist yet:

  "content_scripts": [
    {
      "matches": ["*://*.youtube.com/watch?v=*"],
      "css": ["content.css"],
      "run_at": "document_start"
    }
  ],

content.css:

#watch7-sidebar { display: none !important; }