The Review Cost of all_urls and Broad Host Patterns

What all_urls and *://*/* cost an MV3 extension: in-depth Chrome Web Store review, the all-sites install warning, update re-consent, and how to narrow patterns or move them to optional permissions.

Published October 2, 2026 Updated October 2, 2026 8 min read
Table of Contents

The extension works, the code is clean, and the submission has been “pending review” for eleven days while a competitor’s update went live in two. Or the listing is live but conversion from store page to install is half what you expected. The common cause in both cases is a single line in the manifest: "host_permissions": ["<all_urls>"]. Broad host patterns are sometimes necessary, but they are never free, and the costs land in places teams do not usually measure. This guide quantifies them and shows how to reduce them. It belongs to host permissions and site access.

Why broad hosts are expensive

A host permission is a statement about what the extension could do, and every party that evaluates the extension — the store’s automated checks, its human reviewers, the browser’s install dialog and the user — prices in the worst case. <all_urls>, *://*/*, https://*/* and http://*/* all mean “every page the user visits, including their bank and email”. The Chrome Web Store applies additional, slower review to extensions that request them. The install dialog shows the strongest warning Chrome has: “Read and change all your data on all websites”. Any update that adds such a pattern disables the extension for existing users until they accept the new warning. And because the capability is so broad, any security weakness in the extension becomes a weakness on every site.

Where the cost of a broad host pattern landsReview time at submission, the install warning on the listing, re-consent on updates that add hosts, and the security blast radius for the lifetime of the extension.Store reviewin-depth review pathdays, not hoursInstall conversionall-sites warningfewer installsUpdate re-consentextension disabled until acceptedlost active usersBlast radiusevery site the user visitspermanent
One manifest line, four separate bills.

Step-by-step: narrow the pattern

1. Inventory why each broad pattern exists

1jq '{hosts: .host_permissions, optional: .optional_host_permissions,
2     cs: [.content_scripts[]? | {matches, js}]}' dist/manifest.json

Execution context: a terminal against the built manifest. For each broad pattern, write down the feature that needs it and whether that feature runs automatically or on a user action. In practice a large share of <all_urls> declarations exist for a feature that only runs when the user clicks — which activeTab covers with no warning at all.

2. Replace click-triggered uses with activeTab

1- "host_permissions": ["<all_urls>"],
2+ "permissions": ["activeTab", "scripting"],

Execution context: the manifest. Removing a host pattern never requires user re-consent, so this change is safe to ship in an update. Verify that every feature still works by invoking it from the action, context menu and keyboard shortcut; features that ran automatically will stop and need step 3 or step 4.

3. Enumerate real sites instead of wildcards

If the automatic feature targets a known set of sites — shopping, video, documentation platforms — list them.

1{
2  "host_permissions": [
3    "https://*.amazon.com/*",
4    "https://*.ebay.com/*",
5    "https://*.etsy.com/*"
6  ]
7}

Execution context: the manifest. Chrome’s install warning names the sites (or says “on a number of websites” for long lists), which users accept far more readily than “all websites”. Reviewers can check the list against the store description. Adding a site in a later update does trigger re-consent, so batch site additions rather than shipping one per release.

Install conversion by permission warningIllustrative store-page-to-install conversion for the same extension listing under four permission configurations, from no host warning to all websites.activeTab only31 % of listi…One named site28 % of listi…A number of websites22 % of listi…All websites14 % of listi…
Each step toward 'all websites' costs installs — the steepest drop is the last one.

4. Move genuinely broad features to optional permissions

1{
2  "optional_host_permissions": ["https://*/*"]
3}
1// enable from the options page, in a click handler
2const granted = await chrome.permissions.request({ origins: ["https://*/*"] });

Execution context: the manifest and an extension page. Optional patterns do not appear in the install warning, do not trigger re-consent when added in an update, and are requested from users who have just chosen the feature. Reviewers still see them in the manifest and still expect a justification, but extensions whose broad access is optional and opt-in are generally reviewed as lower risk than those that demand it at install.

5. Write the justification reviewers need

When broad access is unavoidable — an ad blocker, an accessibility tool that adapts every page, a password manager — say exactly why in the listing’s permission justification field and in the description.

1Host permission (<all_urls>):
2Readable adjusts text contrast and font size on every page the user visits, which is
3its single purpose. The content script reads only computed styles and text nodes;
4it does not read form fields, cookies or network data, and sends nothing off the
5device. Users can restrict it to specific sites in Chrome's site access menu.

Execution context: the Chrome Web Store developer dashboard’s privacy tab. Concrete statements about what is not accessed are what reviewers look for. Vague justifications (“needed for functionality”) are a common reason for rejection. More on this in writing a permission justification that passes.

6. Exclude what you never need

Even a broad feature rarely needs every page. Exclude sensitive or irrelevant sites in the content script declaration, which both reduces risk and gives reviewers evidence of care.

 1{
 2  "content_scripts": [{
 3    "matches": ["https://*/*"],
 4    "exclude_matches": [
 5      "https://*.bank.example/*",
 6      "https://accounts.google.com/*",
 7      "https://mail.google.com/*"
 8    ],
 9    "js": ["contrast.js"]
10  }]
11}

Execution context: the manifest. exclude_matches narrows injection but not the host permission itself, so the install warning is unchanged; the value is in reduced exposure and a clearer story for reviewers. A user-editable exclusion list stored in chrome.storage.sync and applied through dynamic registration is even better.

Common mistakes

  • Keeping a debugging wildcard. <all_urls> added “temporarily” while developing a feature is the single most common way a broad host reaches a store submission. Lint the built manifest in CI and fail on broad patterns that are not on an allow-list.
  • Adding broad hosts in a minor update. Every existing user’s extension is disabled until they accept the new warning. If a new feature needs broad access, ship it behind an optional permission instead.
  • Using matches broader than the feature. A content script for one site declared with <all_urls> and a runtime check of location.hostname injects into every page the user visits. Put the site in matches; the browser’s filter is cheaper and safer than yours.
  • Justifying with the feature list. Reviewers want to know why the capability is necessary and what you do not do with it, not a list of features. Write the justification in terms of data accessed and data not accessed.
  • Forgetting file://. <all_urls> includes local files, which reviewers notice. If you do not need them, use https://*/* and http://*/* explicitly.

Cross-browser variation

  • Chrome / Edge: broad hosts trigger in-depth review on the Chrome Web Store and the “all websites” warning. Edge Add-ons applies its own review with similar scrutiny.
  • Firefox: AMO reviews broad hosts carefully, especially combined with remote data. Users see the hosts at install (Firefox 127+) and can revoke them individually afterwards.
  • Safari: App Store review evaluates the containing app; at runtime Safari asks the user per site regardless of what the manifest declares, so broad patterns buy less there than elsewhere.
Pattern choices and their consequencesComparison of activeTab, a list of named sites, optional broad hosts and declared broad hosts on install warning, review scrutiny and update re-consent.ChoiceInstall warningReviewRe-consent on addactiveTabNoneStandardNoNamed sitesNames sitesStandardYesOptional broadAt requestSome scrutinyNoDeclared broadAll websitesIn-depthYes
Optional broad hosts keep most of the capability with little of the cost.

Verification

  1. Load the narrowed build unpacked and open chrome://extensions → Details → “Permissions”: confirm the listed site access matches your intent.
  2. Pack the extension and drag the .crx into Chrome on a test profile to see the exact install warning users will see.
  3. Install the previous published version, then update to the new build locally; confirm Chrome does not disable it for re-consent (removals never do; additions to declared hosts do).
  4. Exercise every feature from every trigger to confirm nothing depended silently on the removed pattern.

FAQ

Is *://*/* treated differently from <all_urls>?

For warnings and review, they are equivalent. <all_urls> additionally matches file:// and ftp:// schemes, which need separate user opt-in for file URLs anyway.

Does requesting broad optional hosts still slow review?

It can draw some scrutiny, because the manifest still declares the capability. In practice, opt-in broad access with a clear justification is reviewed far more favourably than the same access demanded at install.

Can I add hosts later without users noticing?

Not declared ones — users must accept the new warning, and many will not. Optional hosts can be added freely in an update and requested when needed.

Other MV3 Architecture & Extension Lifecycle Resources