I'm working on a Chrome extension with many content scripts. Most of them use the same function(s), so I'd like to share those functions between the content scripts; however I can't seem to figure out how to do it.
Content scripts are sandboxed, so don't have access to the same window
object. It seems there should be an obvious solution, but I haven't been able to find it.

- 6,926
- 5
- 62
- 86
-
They're all in the same isolated world. They can interact with each other just fine. Have you been having trouble getting that to work? – Teepeemm Oct 07 '14 at 16:59
-
1From https://developer.chrome.com/extensions/content_scripts: "isolated worlds allow each content script to make changes to its JavaScript environment without worrying about conflicting with the page or with other content scripts." This implies the content scripts don't share a single isolated world. This is in line with my own findings, but I'd prefer to be wrong! – Protector one Oct 07 '14 at 17:35
-
possible duplicate of [Can I share code between different parts of Chrome Extension?](http://stackoverflow.com/questions/24227874/can-i-share-code-between-different-parts-of-chrome-extension) – Xan Oct 07 '14 at 18:15
-
2@Protectorone That only applies to content scripts from different extensions. If you inject several scripts from one extension, they share the context. – Xan Oct 07 '14 at 18:16
1 Answers
Content scripts are sandboxed, so don't have access to the same window object.
That's not entirely true: although content scripts by default cannot interact with the window
object of the page where they are loaded, they share the same hidden window
object of the "isolated world". So if you load two different content scripts into the same page, you'll be using the same window
for both content scripts.
Here is an example, try it by yourself, and do something like this:
A sample of
manifest.json
:{ "name": "My extension", ... "content_scripts": [ { "matches": ["*://*/*"], "js": ["one.js", "two.js"] } ] }
The script
one.js
with the function:function sayHello(name) { alert("Hello " + name + "!"); }
The script
two.js
that uses that function:sayHello('John');
What happens here?
That's pretty easy to tell:
- When a page is loaded, the content scripts are injected
- The
one.js
script is injected first and defines thesayHello
function - Now
two.js
and any other content script injected afterone.js
can use that function - Calling
sayHello('John');
will alert "Hello John!" as expected.
That's why most of the developers (me too) love doing something like this:
"content_scripts": [
{
"matches": ["*://*/*"]
"js": ["jquery.min.js", "script.js"]
}
]
because that's an easy way to include jQuery and use it with your content scripts.
Obviously content scripts will share the same window
object even if they are injected from the background page with the chrome.scripting.executeScript()
(MV3) or chrome.tabs.executeScript()
(MV2) function.
To answer your question:
You can easily create a script containing all your utilities and most used functions, so you'll always be ready to use them in any other content script injected after the first one.
So, basically, doing something like this:
"content_scripts": [
{
"matches": ["*://*/*"]
"js": ["script1.js", "script2.js", "script3.js", ...]
}
]
means that:
script1.js
is injectedscript2.js
is injected and inherits the namespace ofscript1.js
script3.js
is injected and inherits the namespace ofscript2.js
andscript1.js
- and so on...
Clarifications
When the Google documentation says:
Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.
This means that:
- Content scripts cannot interact with the namespace of the page they are injected to.
- Content scripts cannot interact with the namespace of content scripts injected in the same page by another extension.
But:
- They can interact with the page's DOM.
- They can interact with the namespace of other content scripts injected on the same page by the same extension.
In ManifestV3 content scripts can be loaded in the window
of the page by specifying "world": "MAIN"
in their content_scripts
declaration (Chrome 111 and newer) or when injecting/registering via chrome.scripting API (Chrome 95/102 and newer).

- 63,369
- 21
- 118
- 128
-
2To clarify: what documentation meant was "content scripts from different extensions are isolated". – Xan Oct 07 '14 at 18:24
-
-
This does not really work for me. I can see both scripts being injected and executed in the right order but when the second calls a method defined in the first, i get a method not defined error. – gtato Apr 18 '21 at 15:04
-
-
I know this is an old question, but how do you keep your namespace clean when doing that? – btonasse Jul 13 '22 at 06:40
-
2@btonasse that's up to you really. The simplest way is probably to isolate stuff wrapping it in an anonymous function like: `(function() { /* stuff here */ })()`. – Marco Bonelli Jul 13 '22 at 12:24