• Browser Extension SDK
  • Content Scripts

Content Scripts

Content scripts run in the context of web pages in an "isolated world." This allows multiple content scripts from various extensions to coexist without conflicting with each other's execution.

Use cases:

Adding a single content script

NOTE: Since Plasmo's default Typescript configuration treats all source files as modules, if you don't have any imports or exports in your code, you'll have to add an export {} line at the start of your file. (You will see this warning when creating your first content script!)

Create a content.ts file that exports an empty object and hack away!

export {}
  "You may find that having is not so pleasing a thing as wanting. This is not logical, but it is often true."

Refresh your browser and open any webpage, then open its inspector:


See with-content-script for a full example.

Adding multiple content scripts

Create a contents directory for multiple content scripts, and add your content scripts there. Make sure their names describe what they do!

See with-many-content-scripts for an example.


Sometimes, you'll want to run a content script on a specific page or only on certain pages. You can provide a custom content script configuration by exporting a config object from your content script:

import type { PlasmoContentScript } from "plasmo"
export const config: PlasmoContentScript = {
  matches: ["<all_urls>"],
  all_frames: true

Working with this configuration object is a breeze thanks to the exported PlasmoContentScript type 🥳.

To learn more about the config and each property, check out Chrome's official documentation.

Injecting into the main world

You must inject code into the main world if you'd like to access the window object from your content script. It's not currently possible to declaratively inject content scripts into the main world via the content_scripts manifest field.

Instead, Chrome offers a chrome.scripting.executeScript API that lets you inject content scripts into the main world. First, add the scripting permission into your manifest:

  "permissions": ["scripting"]

Then, inject your content script into the main world by calling chrome.scripting.executeScript from your background service worker:

    target: {
      tabId // the tab you want to inject into
    world: "MAIN", // MAIN to access the window object
    func: windowChanger // function to inject
  () => {
    console.log("Background script got callback after injection")

For the func key, you can pass in a Typescript function from your project, which will automatically convert to a JavaScript function when your extension bundles.

See with-main-world-content-script-injection for an example.

Importing resources

To import external assets into your content script, you can use the url: scheme:

import myFile from "url:./path/to/my/file/something.js"

The url: scheme will automatically resolve the something.js asset and add it to the web_accessible_resources declaration in the built bundle. The above myFile variable will be a string containing the URL to the asset:

> console.log(myFile)
chrome-extension://<your chrome ext id>/something.eb20bc99.js?1656000646313

Alternatively, you can use the data-base64 or the data-text scheme to import and embed the asset directly into your code. For small assets, these schemes should work well.

NOTE: Please see this note about ~ import resolution

Last updated on December 2, 2022