42

Is it possible to inject JS before page load, or is it necessary to use content scripts and way for the document to finish?

For example, is there a faster way to execute JS that turns the page red as soon as it's opened?

Ian McIntyre Silber
  • 5,433
  • 13
  • 52
  • 74

1 Answers1

67

Declare a content script in the manifest file with "run_at": "document_start" to get it to run as soon as possible, i.e. right after constructing the document root (when <head> does not exist yet).

For your very specific example, it might be better to declare a content style instead, similar to content scripts, but using the "css" key instead of "js".

If you want to dynamically run a script as soon as possible, then call chrome.tabs.executeScript when the chrome.webNavigation.onCommitted event is triggered.

Theblockbuster1
  • 169
  • 4
  • 14
Rob W
  • 328,606
  • 78
  • 779
  • 666
  • Special thanks for the reference to `chrome.webNavigation.onCommitted`, much handier than `chrome.tabs.onUpdated`. – cprcrack May 17 '17 at 13:32
  • 1
    @RobW, onComitted runs when "*at least part of the document has been received from the server*". How do we get the moment before that then? The moment right when the user click the address bar and click key [--eg when he's reloading the page, or loading a new one]. – Pacerier Aug 07 '17 at 22:11
  • 1
    @RobW, Separately, the doc writes "*If a navigation was triggered via Chrome Instant or Instant Pages, a completely loaded page is swapped into the current tab*". In such a case, is it still possible to run a script to replace the webpage's `window` object with my own proxy win object right before any webpage code could even run? – Pacerier Aug 07 '17 at 22:17
  • 1
    Btw manifest's document_start contentscript will run before `chrome.webNavigation.onCommitted`, but it has no access to chrome functions available to bg. For bg, `chrome.webNavigation.onCommitted` is still the earliest way. – Pacerier Aug 08 '17 at 04:25
  • 1
    With the executeScript API, there is no guarantee that your script runs in time. If this is important, declare a script in manifest.json – Rob W Aug 08 '17 at 08:58
  • Btw I made some tests for a https page https://pastebin.com/gJMDQw9P, and a http page https://pastebin.com/Yb2GSNzW. All code tested on a 60.0.3112.78 (Official Build) (64-bit), Mac OS X, V8 6.0.286.44. (I didn't test on ftp and file pages.) I found a **chrome bug** whereby manifest cs is sometimes not run. This bug is found not on a httpS page, but on a http page. Without manifest cs and webrequests callbacks running, the earliest point in time is and its too late by... – Pacerier Aug 10 '17 at 02:37
  • ...then, because if I wanted to replace `window` of the page with a proxy, the website could have already obtained a reference to the original `window` object before I managed to replace it. – Pacerier Aug 10 '17 at 02:38
  • As for the bg page, my tests above show that it's not true that the earliest point in time is `chrome.webNavigation.onCommitted`. **~~~** The httpS tests show that while nv onBeforeNavigate and r onBeforeRequest occurs before the page, the earliest point in time after the page may have been either r onBeforeSendHeaders, r onSendHeaders, r onHeadersReceived, r onResponseStarted, r onCompleted, or . **~~~** The http tests show that sometimes the earliest point may even be nv onBeforeNavigate or r onBeforeRequest. – Pacerier Aug 10 '17 at 02:49
  • Hmm, as for my comment on https://stackoverflow.com/questions/19191679/chrome-extension-inject-js-before-page-load/19192010#comment78166411_19192010, perhaps webrequests would not have been ignored had they been **blocking** webrequests. Need to test. – Pacerier Aug 10 '17 at 04:42
  • And also, have manifest js set may more often show cases where `executeScript` works for the events before `chrome.webNavigation.onCommitted`. – Pacerier Sep 11 '17 at 22:24
  • Btw, is manifest js document_start **guaranteed** to run at start? Or is it at an [at-best](http://archive.is/bgTJ8#selection-11063.5-11063.12) basis like executeScript? – Pacerier Sep 11 '17 at 22:32
  • @RobW, Btw I tried this script `document.documentElement.appendChild(document.createElement('script')).innerHTML = 'window.open=null;document.createElement=null'` in manifest js doc start, which works.. but `document.documentElement.appendChild(document.createElement('script')).innerHTML = 'document=null;window=null'` doesn't. Do you know how can `window` and `document` be overridden? – Pacerier Sep 11 '17 at 22:50
  • Ref https://stackoverflow.com/questions/12095924/is-it-possible-to-inject-a-javascript-code-that-overrides-the-one-existing-in-a/12096099#comment80379957_12096099 – Pacerier Oct 12 '17 at 18:55
  • Links are broken (404) and `chrome.webNavigation` is undefined – dustytrash Jan 15 '21 at 01:40