Need help in injecting script to page head before DOM gets executed

3,216 views
Skip to first unread message

yureshwar ravuri

unread,
Jun 24, 2021, 7:39:48 AM6/24/21
to Chromium Extensions
Hi,

We are working on an Open Source Chrome extension: Digital Assistant Client

I was trying to inject a script into a webpage with chrome extension before the page starts loading the dom using "content script" and "run_at": document_start. But seems like the page dom is loading before my script is injected. I am doing this in manifest version 2.

In manifest.json I have declared like this
{
"matches": ["*://*"],
"js": ["js/injectscriptmodifier.js"],
"all_frames": false,
"run_at":"document_start"
},

The Injectscriptmodifier.js consists of the below code
var s = document.createElement('script');
var scriptpath = chrome.extension.getURL('js/links.js');
s.src = scriptpath;
s.onload = function() {
};
(document.head || document.documentElement).appendChild(s);

And the links.js has mutationobserver and addeventlistner modification to capture the clickable links and buttons that the page has
EventTarget.prototype.addEventListener = function (addEventListener) {
return function () {
if (arguments[0] === "click") {
UDAAddNewElement(this);
}
addEventListener.call(this, arguments[0], arguments[1], arguments[2]);
}
}(EventTarget.prototype.addEventListener);
var UDAObserver = new MutationObserver(UDADomMutations);
// starting the mutation observer
UDAObserver.observe(document, {
childList: true,
subtree: true
});

When the page is loaded some of the clickable links/buttons are not getting captured and when I check the first detected object it shows somewhere in the middle of the page. I suspect that "run_at": "document_start" is not stopping the dom to be executed at first. Sometimes when I refresh then the script gets injected properly and the extension works as expected. Any help in this regard is very helpful.

Thanks & Regards,
Yureshwar Ravuri
Mob: +91 9030003889
Mail: yure...@gmail.com

Alexei Miagkov

unread,
Jun 24, 2021, 12:58:41 PM6/24/21
to yureshwar ravuri, Chromium Extensions
The way you inject the script introduces a delay. You can avoid this delay by including the contents of "js/links.js" inside your content script as a string (example of converting a function to a string), and then setting the "text" property of your injected script to that string (example).

Also, you already have access to the DOM from your isolated world content script. Do you actually need to inject into the page script context?

--
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/CALcj%3D2yht6%3D92t-Q307Ar%2BZUerfEK-7PDojJPsqMoSCqSF2xyg%40mail.gmail.com.

yureshwar ravuri

unread,
Jun 24, 2021, 7:18:46 PM6/24/21
to Alexei Miagkov, Chromium Extensions
Why I am injecting the script to the page is we show some menu inside the page itself and we record the user clicks. For that we constantly monitor the page dom clickable nodes. Nodes cannot be sent from the content script to the page with postmessage. That's why I am injecting the script to the page. If it can be achieved with post message let me know how I can approach it. 

yureshwar ravuri

unread,
Jun 24, 2021, 7:21:03 PM6/24/21
to Alexei Miagkov, Chromium Extensions
Also we use the same code base as individual sdk so that's why I m injecting with file. 

yureshwar ravuri

unread,
Jun 29, 2021, 1:03:40 AM6/29/21
to Alexei Miagkov, Chromium Extensions
Hi Alex,

Initially, I was trying with chrome execute script which runs at document_idle inside background script with as given below. But we are unable to detect the clickable objects when the dom is getting parsed and we have moved to content script inclusion type.

chrome.tabs.executeScript(tabs[0].id, {
file: "UDAPluginSDK.js",
runAt: "document_idle",
}, function() {});

Our extension needs some of the scripts to be loaded onto the page for performing node operations like converting actual node object to json data and adding some UI to the page itself like given below which has right-side panel opened. In order to do that we are injecting an sdk to the page where it adds the HTML to the actual page and alters the page appearance. Please see how our panel shows on the right side as shared in the screenshot below.

image.png

If we move to isolated world context then there are two problems 
1. Passing the domnode from one script to another script using postmessage
2. Injecting scripts and css to the page is not happening.
 
Could you please let me know whether we should do with isolated content script only inorder to remove the delay in loading the script or is there any alternative for this?


Thanks & Regards,
Yureshwar Ravuri
Mob: +91 9030003889
Mail: yure...@gmail.com

Alexei Miagkov

unread,
Jun 29, 2021, 10:18:28 AM6/29/21
to yureshwar ravuri, Chromium Extensions
I am not sure you understood my original suggestions.

The delay: "document_start" is not the problem, you want "document_start" if you want to be there before anything else happens. You introduce a delay when you inject a script with src set to a chrome extension URL. You might think there would be no delay because you're not loading a resource over the network, but no, there is a delay because the browser still needs to fetch something (your chrome extension resource) and while that fetching is happening, the page goes on loading.

If you actually need to inject a script tag into the page where you want your script to run before anything else on the page loads, you need to set the script's contents using the text attribute, not the src attribute. You probably also want to set the async attribute to false. I previously sent a link to an example from Privacy Badger.

But if you may not actually need to inject this script tag at all. You only need to pierce the isolated JS context you get by default in your content scripts if you want to interact with the page's JS environment. For example, you want to override the user agent property in the navigator object. You already have access to the DOM, you can already read/write to page DOM, create interactive elements, listen to clicks, etc. You just can't see/modify JS variables used by the page, and the page can't see your JS, which is a good thing.

I think you should make a simple extension just to practice and verify your approach. Don't complicate things right away with your project SDK and other big project-specific requirements. Make an extension that injects a before-anything-else-happens content script and listens for user clicks and passes that info back to the background page.

yureshwar ravuri

unread,
Jul 1, 2021, 1:36:00 AM7/1/21
to Alexei Miagkov, Chromium Extensions
Hi Alex,

Thanks for your response. I have understood your original suggestions. Yes you also got my point on the delay of injecting the script and yes I may need to run the scripts in an Isolated way approach which makes page code also separated. Thank you once again for your inputs.

Thanks & Regards,
Yureshwar Ravuri
Mob: +91 9030003889
Mail: yure...@gmail.com

Yureshwar Ravuri

unread,
Nov 5, 2021, 3:18:02 AM11/5/21
to Chromium Extensions, Yureshwar Ravuri, Chromium Extensions, Alex
Hi alex,

Thank you for helping me out. Your approach on injecting the script as text has helped me out. It removes the delay in getting the script.

Thank you
Yureshwar
Reply all
Reply to author
Forward
0 new messages