"Either Chrome injects your script on every matching URL automatically (declarative), or your service worker injects it the moment something interesting happens (programmatic). Lesson 2 is about picking the right door for the room you're entering."
Declarative — Manifest Says So
The simpler path: list the script in manifest.json under content_scripts. Chrome reads the list at install time and injects on every navigation that matches. No background.js code, no permission prompts beyond what the manifest already declared, no per-tab decisions. Just "this script runs on these URLs."
Each entry is one logical content script. The fields you'll actually use:
matches— required. Array of URL match patterns (https://*.github.com/*,<all_urls>, etc.).exclude_matches— optional carve-outs frommatches.js— array of script files inside the extension package.css— array of stylesheet files; injected the same way.run_at—document_start(before DOM parse),document_end(DOM ready, resources still loading),document_idle(everything settled — the default).all_frames— boolean, false by default. True if you need to reach inside iframes.world—ISOLATED(default, Lesson 3 covers it) orMAIN(Chrome 111+, run in the page's own JS world).
Programmatic — chrome.scripting.executeScript
The on-demand path: don't list the script in the manifest, inject it from the service worker when something triggers. Toolbar icon click, context menu activation, message from popup, alarm fire, whatever — the SW calls chrome.scripting.executeScript and pushes a function or file into a specific tab.
This is the right tool when:
- The script should run sometimes, not on every page load.
- You want a return value —
executeScriptreturns the result of the injected function back to the SW. - You need to choose which tab or which frame, based on logic that the manifest can't express.
It costs you the "scripting" permission plus host permissions for the URLs you want to touch — Track 6 walks through the permission model.
The activeTab Shortcut
For toolbar-click injection on the current tab, "activeTab" is a special permission that grants temporary host access without prompting the user. It activates when the user clicks the toolbar icon (or triggers a context menu / keyboard shortcut) and lasts for that tab until navigation. This is the Chrome-recommended path for opt-in extensions — no scary <all_urls> warning, just "works on the page you're on right now if you ask."
Combining Both
It is completely valid (and common) to use both. ClipDeck's eventual shape:
- Declarative for the always-on selection capture — every page, listening for the user's selection so we can save it when they ask.
- Programmatic for one-off operations — "extract the article body of this page," "highlight the saved clips on this page," triggered by the toolbar icon or popup button.
ClipDeck Track 3 Choice
For the Track 3 milestone — saving the user's selected text — declarative wins. The script needs to be listening on every page so the selection is already in scope the moment the user invokes the save action. Programmatic injection would race with the user's intent: by the time the SW finishes injecting, the selection might be gone (clicking the toolbar collapses popups, sometimes clears selections). Declarative + match <all_urls> + activeTab as a fallback for sensitive sites is the canonical ClipDeck shape.
<all_urls> install warning. A manifest with "matches": ["<all_urls>"] triggers Chrome's "Read and change all your data on all websites" install prompt — the scariest one users see. Use it only when you genuinely need to. Prefer narrower patterns (https://*.github.com/*) or activeTab + programmatic injection where possible. The Chrome Web Store review will also push back on broad host permissions without clear justification.