Accessing Parent Page JavaScript Functions And Variables From A Chrome Extension

Chrome extensions are one of those toys which once you learn to develop it’s hard to stop. I’ve written a bunch of small improvements to various sites I visit on a regular basis, usually simple changes, but one recent endeavour had me scratching my head for a bit.

Isolated Worlds

Chrome Extension Content Scripts (JavaScript code that runs on whatever websites your extension is made to run on) execute in what Google call Isolated Worlds, that is, a special environment where the script is able to access and modify the DOM, but is not able to access JavaScript functions and variables of that page. This is described in the content script documentation as follows:

Isolated worlds do not allow for content scripts, the extension, and the web page to access any variables or functions created by the others. This also gives content scripts the ability to enable functionality that should not be accessible to the web page.

There is a simple way to circumvent this if your extension requires it, while it is a little crude it gets the job done. Let’s start with a rather contrived but simple example.

<!DOCTYPE html>
    <head>
        <script type="text/javascript">
            const data = "The quick brown fox jumps over the lazy dog"
            function logHelloWorld() {console.log("Hello World")}
        </script>        
    </head>
    <body>
        <h1>Chrome Extension Example</h1>
        <div id="content"></div>
    </body>
</html>

We have a webpage that has some JavaScript, a variable called data, and a function called logHelloWorld that writes “Hello World” to the console. Let’s say that our extension needs to access both of these, we want to write the data variable content to the page so it’s visible, and we want to execute the function.

We may write something like the following in our content script.

// dumping data to the page
h2 = document.createElement('h2')
h2.innerText = data // referencing the data variable defined in the page
document.getElementById('content').appendChild(h2)

// executing logHelloWorld
logHelloWorld() // referencing the logHelloWorld defined in the page

If we paste the above code into the Chrome developer console it works as expected. The data string is appended to the content div, and the logHelloWorld function writes to the console.

Chrome Example

However, putting the same code into an extension content script results in a terminating error.

Chrome Not Working Example

This is due to the Isolated World execution environment - our extension does not have access to functions and variables defined in the page.

Injecting script tags into the DOM

The way we can circumvent this is instead of having our content script execute in its special environment, we append our code to the DOM inside a <script> tag which will cause the browser to run it within the context of the page, giving it access all page variables and functions.

Let’s try the following.

const injectedCode = `
h2 = document.createElement('h2')
h2.innerText = data
document.getElementById('content').appendChild(h2)

logHelloWorld()
`
var script = document.createElement("script");
script.textContent = injectedCode;
(document.head).appendChild(script);

This once again gives us the result we want!

Chrome Working Example

The only modification we’ve made is to convert our JavaScript code to a string, and append it to the DOM. Alternative methods may be to add an Event Listener and execute on a click or other event.


Share this post on , , , or