google-chrome-extensionchrome-extension-manifest-v3

Chrome Extension Manifest v3: Load content script only on click on extension icon (minimize permissions)


I am migrating a functioning browser extension to manifest v3. The problem: I want the content script to be loaded only upon clicking on the browser extension icon. However, the script is always loaded. When I try to upload to the chrome store, I get the following message, which is what I want to avoid:

Because of the host permission, your extension may require an in-depth review that will delay publishing.

I suspect it has something to do with the "action", but I could not figure out on how to fix this. Here is the manifest:

{
    "manifest_version": 3,
    "name": "__MSG_extName__",
    "description": "__MSG_extDescription__",
    "key": "...",
    "version": "1.0.0",
    "icons": { ... },
    "background": {
        "service_worker": "/background.js"
    },
    "permissions": [
        "storage"
    ],
    "content_scripts": [
        {
            "matches": [
                "<all_urls>"
            ],
            "js": [
                "/content.js"
            ]
        }
    ],
    "web_accessible_resources": [
        {
            "resources": [
                "/assets/*",
                "/options.html"
            ],
            "matches": [
                "<all_urls>"
            ]
        }
    ],
    "options_page": "options.html",
    "action": {}
}

One last note: I assume that I need activeTab permission. But again, my problem is that I want to minimize the required permissions.

Thanks in advance!


Solution

  • I eventually figured it out. Basically, I had to remove the "content_scripts" section. Instead, I need to inject the content script explicitly with the action handler. I was under the wrong assumption that I could constraint the content_scripts section with the right permissions.

    For this to work, I had to set activeTab and scripting permissions, here the new permissions:

    "permissions": [
        "storage",
        "activeTab",
        "scripting"
    ],
    

    I already had an action handler in my service worker (background.js), which now looks like this:

    chrome.action.onClicked.addListener(async (tab) => {
      await chrome.scripting.executeScript({
        target: { tabId: tab.id, allFrames: true },
        files: ["content.js"],
      });
      // Do other stuff...
    });
    

    I hope this answer will help someone, somewhere!