Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

PSA: userScripts.execute() and multiple world support in User Scripts API

205 views
Skip to first unread message

Oliver Dunk

unread,
Feb 6, 2025, 5:53:12 AMFeb 6
to Chromium Extensions
Hi all,

I'm excited to share two additions to the User Scripts API - one which is available behind a flag in Chrome Canary, and one which is available in Chrome 133 stable starting this week.

New method: userScripts.execute

Following the addition of the User Scripts API in Manifest V3, we heard from many developers that they often need to inject a script based on a user action. This was not easy to do with the existing API which required that all scripts were registered ahead of time and injected into new pages.

Together with the WebExtensions Community Group, and with help from engineers at Firefox, Safari and Edge, we designed a new `userScripts.execute()` method that can run a script immediately on the specified target.

We'd love to hear your feedback before this ships by default - you can try it out by starting Chrome Canary with the `--enable-features=ApiUserScriptsExecute` flag.

You can call the API as follows:

```
chrome.userScripts.execute({
    target: { tabId: tab.id },
    js: [{ code: "alert('hi')" }]
});
```

Find the full API described in the WECG proposal.

Multiple user script world support

When a non-extension script runs in a page, it runs in the "MAIN" world. Extension content scripts are run in the "ISOLATED" world which is isolated from other scripts and extensions. This means code on a web page cannot (unintentionally, or maliciously) change global values that the content script will access. With the introduction of the User Scripts API, we introduced a third user script specific "USER_SCRIPT" world. This allows user scripts to be isolated from both content scripts and main world scripts.

The new “USER_SCRIPT” world was an improvement over Manifest V2, but individual user scripts still shared the same world. To make it possible to isolate individual user scripts, starting in Chrome 133, the `worldId` parameter can be used to run each user script in a unique world. This isolates user scripts from each other, and prevents one user script from interfering with a different one.

You can also use this parameter when setting configuration for a world:

```
chrome.userScripts.configureWorld({
  csp: "",
  messaging: true,
  // You can now specify a world ID.
  worldId: "example"
});
```

To access or reset this configuration, we've added new `getWorldConfigurations()` and `resetWorldConfiguration()` methods.

We worked on these changes in the WebExtensions Community Group - you can find the proposal here.

These changes are available and shipping by default in Chrome 133.

As always, please do let us know if you have any feedback. We're excited to keep bringing you these changes and are always looking to make improvements where we can.

Thanks,
Oliver on behalf of Chrome Extensions DevRel

hrg...@gmail.com

unread,
Feb 6, 2025, 3:30:18 PMFeb 6
to Chromium Extensions, Oliver Dunk
Is the "userScript" permission the only requirement to use this?
For example, if the user activates some functionality in my extension that requires the userScript API, can I request the "userScript" permission at that moment and then expect everything to just work?

Alexei Miagkov

unread,
Feb 6, 2025, 6:52:07 PMFeb 6
to Oliver Dunk, Chromium Extensions
>This was not easy to do with the existing API which required that all scripts were registered ahead of time and injected into new pages.

What's the difference between userScripts.execute() and scripting.executeScript()? Is it "func" vs. "code"? scripting.executeScript can also "run a script immediately on the specified target". It's confusing to have multiple ways to do almost the same thing.

--
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 visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/18ad9948-7650-44fd-a703-fef11088b1dan%40chromium.org.

hrg...@gmail.com

unread,
Feb 6, 2025, 8:02:42 PMFeb 6
to Chromium Extensions, Alexei Miagkov, Chromium Extensions, Oliver Dunk
What's the difference between userScripts.execute() and scripting.executeScript()?

scripting.executeScript() can only execute code that's already present in the extension package, and so it's subjected to the CWS code review.
userScripts.execute(), on the other hand, can execute an arbitrary string of code that's not known at review time.

In MV2, there is one function to do both, which is problematic for the CWS code reviewers.

Oliver Dunk

unread,
Feb 7, 2025, 4:54:58 AMFeb 7
to hrg...@gmail.com, Chromium Extensions, Alexei Miagkov
Yeah, the `userScripts.execute` method is unique in that it allows for running arbitrary code. I do agree that they feel very similar - and honestly, they share a lot of the same implementation too. Hopefully this is an improvement though since the workarounds for running user scripts based on a user action weren't ideal.

Is the "userScript" permission the only requirement to use this?

That's the only API permission you need. You'll also need host permissions for whatever site you want to run on (which should include `activeTab`). 
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

hrg...@gmail.com

unread,
Feb 7, 2025, 7:09:45 PMFeb 7
to Chromium Extensions, Oliver Dunk, Chromium Extensions, Alexei Miagkov, hrg...@gmail.com
That's the only API permission you need. You'll also need host permissions for whatever site you want to run on (which should include `activeTab`).

So, the "developer mode" global switch won't be required?

Oliver Dunk

unread,
Feb 10, 2025, 4:44:19 AMFeb 10
to hrg...@gmail.com, Chromium Extensions, Alexei Miagkov
The only API permission you need is the userScripts permission, but developer mode does need to be enabled as well. That's the case for all methods in the userScripts namespace which is inaccessible without it.

I know it has taken some time, but we are still looking at the feedback on the developer mode requirement. We still want users to opt-in to the API but we are looking into other options (for example a per-extension toggle).
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

hrg...@gmail.com

unread,
Feb 10, 2025, 4:55:41 PMFeb 10
to Chromium Extensions, Oliver Dunk, Chromium Extensions, Alexei Miagkov, hrg...@gmail.com
A per-extension switch on the details page would certainly improve the situation as it solves one of the problems with a global switch, that is, it's all or nothing.
Unfortunately, it still makes the whole situation confusing for the user. The user will wonder things like:
  • What's the difference between the permission and the switch on the details page?
  • If I disable the switch, does the permission get revoked too?
  • If both the permission and the switch are required, what's the point of 2 authorization mechanisms when one would be enough? There has to be a difference between the two, right? (no there isn't, both do the same, but the user won't guess that)
It's confusing.
It also makes the UI flow complicated because once the user grants the permission, the extension will have instruct the user to go to some other page and click on some checkbox, and then comeback to the extension page.

As it's been suggested in the past, the "userScripts" permission should be strictly optional, that is, it MUST NOT be requested at install-time, but only after installation.
It's well known that users just accept anything at install-time, they don't read the terms and conditions or the required permissions or anything, they just accept... accept... accept...
By forcing extensions to request the permission when the user interacts with the UI; this will force the user to pay attention to what is being requested and they will relate the permission request to the UI context in which it's being requested.

It would also be safer that the "userScripts" permission must be requested in isolation, not as part of a group of permissions. The rationale for this is that when an extension asks several permissions in a single dialog box, it's difficult for the user to understand all the blah, blah being presented on the dialog. Whereas a dialog with a single request is much more likely to be understood by the user.

One final suggestion. The details page should show the list of permissions that the user has granted, both mandatory and optional. Next to each optional permission, there should be a checkbox for the user to revoke the permission. This would give the user better understanding of the situation. That is, each extension has a set of mandatory permissions and a set of optional permissions that the user can allow or disallow as they please.

Oliver Dunk

unread,
Feb 11, 2025, 6:50:14 AMFeb 11
to hrg...@gmail.com, Chromium Extensions, Alexei Miagkov
As always, the feedback is really appreciated.

The proposal you've mentioned sounds very close to the behavior Firefox is planning to implement for this API: https://bugzilla.mozilla.org/show_bug.cgi?id=1917000#c1

I'm personally a fan of that approach, but our team's view is that a permissions prompt (even with tweaks) is not sufficient consent for this API. It's less likely any change that involves more reliance on the permissions UI would be something we'd implement.

I am very keen for us to move closer to the proposed Firefox behavior in other ways. For example, we're considering making `chrome.userScripts` undefined when the toggle is off, rather than throwing an error as we do today. I'd also love for APIs like `permissions.has` to take into account the toggle state but that is slightly trickier and I think there are arguments for and against it given how things work in Chrome.
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

Tom Doan

unread,
Feb 11, 2025, 12:54:44 PMFeb 11
to Chromium Extensions, Oliver Dunk, Chromium Extensions, Alexei Miagkov, hrg...@gmail.com
For example, we're considering making `chrome.userScripts` undefined when the toggle is off, rather than throwing an error as we do today.

This would break any extension that uses the official sample code relying on throw/catch (isUserScriptsAvailable()), so be sure to make a lot of announcements, and update the reference docs.

Oliver Dunk

unread,
Feb 11, 2025, 12:58:50 PMFeb 11
to Tom Doan, Chromium Extensions, Alexei Miagkov, hrg...@gmail.com
be sure to make a lot of announcements, and update the reference docs

Yes, absolutely - good callout. To be clear this is still just something we're discussing, but we'll absolutely make sure to communicate before making any changes there.
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

Oliver Dunk

unread,
Mar 17, 2025, 10:12:24 AM (3 days ago) Mar 17
to Tom Doan, Chromium Extensions, Alexei Miagkov, hrg...@gmail.com
Hi all,

The mentioned `userScripts.execute` API is available by default starting in Chrome 135, currently in beta.

Excited to share that!

Thanks,
Oliver Dunk | DevRel, Chrome Extensions | https://developer.chrome.com/ | London, GB

Reply all
Reply to author
Forward
0 new messages