Browser StudioBrowser Studio
October 18, 2026·7 min read·Userscripts

Userscripts vs Chrome extensions: when to build which

Userscripts and Chrome extensions can both change a website. Here's how they differ on permissions, install friction and distribution, and when to build which.


If you want to change how a website behaves, add a button, hide a panel, export a table, you have two ways to ship that change to a browser: a userscript or a Chrome extension. They overlap more than most developers expect. Both run your JavaScript on pages you choose. Both can read and change the page. The differences are in who installs what, what the code is allowed to do, and how it reaches people.

This guide lays out those differences so you can pick the right one before you write a line of code. If you already know you want a userscript, the free userscript header generator and @match pattern tester will save you some trial and error.

What a userscript is

A userscript is a single JavaScript file with a metadata block at the top. It runs inside a userscript manager, an extension such as Tampermonkey, Violentmonkey or Greasemonkey, which reads the header and injects the script into matching pages.

// ==UserScript==
// @name         Wider article column
// @match        https://example.com/articles/*
// @grant        none
// ==/UserScript==

document.querySelector("main")?.style.setProperty("max-width", "none")

The header does the work a manifest does for an extension. @match says where the script runs, @grant lists the extra functions it needs from the manager, such as GM_setValue for storage or GM_xmlhttpRequest for cross-site requests, and @run-at says when to inject it.

Everything else is ordinary DOM code. There's no build step, no packaging and no review queue.

What a Chrome extension is

A Chrome extension is a package: a manifest.json, a service worker, optional content scripts, popups, side panels and options pages. Under Manifest V3 the package is reviewed by the Chrome Web Store before it reaches users, and the extension can only run code that ships inside it.

An extension can do far more than change a page:

  • run a background service worker that reacts to browser events;
  • use chrome.* APIs for tabs, storage, alarms, context menus, downloads and the side panel;
  • add its own interface in the toolbar, a popup or the side panel;
  • work across many sites at once and keep state between them.

If the manifest is new to you, our generator builds a valid Manifest V3 file from a form.

Permissions and install friction

This is where the two differ most for the person installing.

An extension asks for permissions at install time. If it needs to read and change data on every site, Chrome says so in the install prompt, and that warning costs installs. Many developers spend real effort narrowing their host permissions for exactly this reason.

A userscript inherits the manager's permissions. The user has already installed Tampermonkey, which can run on any site. Installing your script is one more click inside the manager, which shows the script's @match lines and grants, and that's all. For a small, single-site change, the friction is much lower, as long as the person already has a manager.

That last condition matters. For someone who has never installed a userscript manager, your script needs two installs, the manager and the script, plus one Chrome setting, described below.

Distribution

Extensions are distributed through the Chrome Web Store. You get a listing page, search, ratings, automatic updates and a review step. You also get the store's rules on single purpose, permissions and privacy disclosures.

Userscripts are distributed as a .user.js link. When someone opens a URL ending in .user.js with a manager installed, the manager offers to install it. You can host the file on GitHub, a gist, or a script directory such as Greasy Fork, and managers can check that URL for updates when the @version changes. There's no review step, which makes publishing fast, and also means users have to trust the code themselves.

Manifest V3 and chrome.userScripts

Manifest V3 changed the ground under userscript managers. An MV3 extension can't execute code that wasn't in its package, and a userscript is, by definition, code the user supplies after install. Chrome's answer is the chrome.userScripts API, which lets an extension register user-supplied scripts to run in a separate USER_SCRIPT world.

The API comes with a switch the user controls. As of October 2026, Chrome's documentation says:

  • Chrome 138 and later: the user must turn on Allow User Scripts on the extension's details page, at chrome://extensions. If it's off, the API isn't available to the extension.
  • Before Chrome 138: the user had to turn on Developer mode on chrome://extensions instead.

For you, this means two things. Anyone running your userscript in a modern manager has flipped that switch. And anyone who hasn't will see your script do nothing, with no obvious error, which is worth a line in your install instructions.

A decision guide

There's no rendered table here, so here's the same comparison as pairs.

  • One site, a small change, for you or a few people: userscript. It takes minutes, needs no packaging, and you can change it and reload.
  • Many sites, background work, or browser events like tab changes and alarms: extension. Userscripts only run inside pages.
  • Your own interface outside the page, such as a toolbar popup or side panel: extension.
  • Distribution to non-technical users at scale: extension. A Web Store listing is one click, a userscript is a manager install plus a setting plus your script.
  • A prototype you want to test this week: userscript. You can always move the DOM code into a content script later.
  • Cross-site requests: both can, an extension through host permissions, a userscript through GM_xmlhttpRequest and a @connect line.
  • Storage: both can, an extension with chrome.storage, a userscript with GM_getValue and GM_setValue.

The common pattern is to start with a userscript and graduate to an extension once the idea has proven itself. We wrote up that path in Prototype your Chrome extension idea as a userscript first.

Getting @match right

Most userscripts that "don't work" are running on no pages at all. The @match line uses Chrome's match-pattern rules, which are stricter than they look:

  • *://example.com/* matches http and https only, not file.
  • https://*.example.com/* matches example.com itself as well as its subdomains.
  • https://example.com with no path is invalid. End it with /*.
  • A * can only be the whole host or the first label, so https://a.*.com/* is invalid.

Paste your patterns and a few real URLs into the @match pattern tester and you'll see each mistake explained before you install anything.

Where AI fits

Both formats are now often written with AI help. For userscripts there's a particular trap: a chat assistant that has never seen the page guesses the page's structure, and the guessed selectors fail silently. Tools that read the page before writing do much better. ScriptPanda, an AI userscript builder built by our studio, works from a trimmed outline of the page you're on, writes the userscript, installs it and lets you ask for fixes when the site changes. It's one option among several, and we compare them honestly in our roundup of AI tools for building browser extensions.

The short version

Choose a userscript when the change lives inside one site's pages and the people using it are comfortable with a manager. Choose an extension when you need browser-level features, your own interface, or a one-click install for a broad audience. When you're not sure, prototype as a userscript: it's the cheapest way to learn whether the idea works, and the hardest part, the DOM code, carries straight over.

Keep going

Know why your users uninstall.

One line of code. Structured feedback. Drop-off funnels.

Start free