"Every permission you declare is a sentence in the install prompt the user reads. Lesson 1 is the model — three categories, two grant moments, one Chrome that calculates the warning text from your manifest verbatim."
The Three Categories
- API permissions — declared in
permissionsarray. Each unlocks achrome.*namespace:"storage"enableschrome.storage.*,"scripting"enableschrome.scripting.*,"contextMenus"enables menus, etc. - Host permissions — declared in
host_permissionsarray. Each is a URL match pattern (https://*.github.com/*,<all_urls>). Grants the extension permission to inject scripts into, read DOM from, and intercept requests on those origins. - Optional permissions — declared in
optional_permissionsAND/ORoptional_host_permissionsarray. Same shape as the two above, but the user is NOT prompted at install. Your code requests them at runtime viachrome.permissions.request.
MV3 separated host permissions from API permissions specifically so Chrome can show a cleaner install warning. The user sees "This extension can: read your data on github.com," not "This extension can: read your data on github.com AND use storage AND use tabs" — those distinct lines, distinct visual weights.
The Two Grant Moments
- Install-time: everything in
permissionsandhost_permissionsis granted when the user installs the extension. The install dialog summarizes everything you've declared; if the user clicks Add, you have it forever (until uninstall). - Runtime: anything in
optional_permissionsoroptional_host_permissionsis granted only when you callchrome.permissions.requestfrom a user-gesture handler. A small dialog appears; the user clicks Allow or Deny. If denied, the API stays unavailable; if allowed, it works for the rest of the session and persists across browser restarts.
How Chrome Computes the Install Warning
Each permission maps to one of a few warning categories. Combining permissions can collapse the warnings (e.g., 'tabs' subsumes some weaker permissions) or add scary ones (anything with <all_urls> ends up under 'Read and change all your data on all websites'). The exact mapping is in the Chrome Developers docs, but the rule of thumb is:
storage,activeTab,contextMenus,sidePanel,commands,omnibox— quiet, no install warning of their own.tabs— moderate, "Read your browsing history."scripting, host permissions narrower than<all_urls>— "Read and change your data on specific sites."<all_urls>in host_permissions OR content_scripts.matches — the loud "Read and change all your data on all websites."downloads,notifications,identity,history,geolocation,cookies— each adds its own dedicated warning line.
The Principle of Least Privilege
The Chrome Web Store review (and informed users) judge extensions by their install warning. Every line you can remove is one fewer reason to refuse. ClipDeck's actual needs:
storage— essential, always declared, no scary warning.tabs— for reading tab.url in the SW. Mildly scary warning, but necessary for the visit counter and per-site clip filter.scripting+activeTab— for programmatic injection on toolbar click.activeTabmeans we can skiphost_permissions: [<all_urls>]for the on-demand path.sidePanel,contextMenus— quiet.- Content scripts declared with
matches: [<all_urls>]— this is what's giving ClipDeck its 'all websites' warning. Track 6 Lesson 3 discusses narrowing this. downloadsfor export — should go inoptional_permissions, requested only when the user clicks Export.
permissions for API, host_permissions for URLs, optional_* for the lazy versions.