Chrome Extension Content Script Isolation — Developer Guide

4 min read

Content Script Isolation Deep Dive

Introduction

The Isolated World Model

What Content Scripts CAN Access

What Content Scripts CANNOT Access

Accessing Page JavaScript

Method 1: window.postMessage

// content.js — send to page
window.postMessage({ type: "FROM_EXTENSION", data: "hello" }, "*");

// content.js — receive from page
window.addEventListener("message", (event) => {
  if (event.data.type === "FROM_PAGE") {
    console.log("Page says:", event.data.data);
  }
});

// inject.js (injected into page context)
window.addEventListener("message", (event) => {
  if (event.data.type === "FROM_EXTENSION") {
    const result = window.myApp.getData(); // Access page JS!
    window.postMessage({ type: "FROM_PAGE", data: result }, "*");
  }
});

Method 2: Main World Injection (MV3)

// background.js — inject script into main world
chrome.scripting.executeScript({
  target: { tabId: tab.id },
  world: "MAIN",  // Runs in page's JS context!
  func: () => {
    return window.myApp.getState();
  }
});

Method 3: Script Tag Injection

// content.js — inject a script tag into the page
const script = document.createElement("script");
script.src = chrome.runtime.getURL("inject.js"); // Must be web_accessible_resource
document.head.appendChild(script);

Communication Architecture

Page JS <-- window.postMessage --> Content Script <-- chrome.runtime --> Background SW

CSP and Content Scripts

Debugging Isolation

Security Best Practices

Common Patterns

Common Mistakes

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.