-1

I want to know whether the current tab is an old tab which was opened before installing the extension or is that a special tab (browser UI, extension page, chrome.google.com) where I can not inject the content script.

There's a partial solution where I try to send message to the content script and if it throws an error (i.e. content script is not loaded on the page) then it's either an old tab or a special page. I need a way to know which one is it so that I can inform via popup page.

Detecting if browser extension popup is running on a tab that has content script

There is possibly one more way: try to execute script on page, if it succeeds then it was an old tab but this would need one more permission in manifest i.e. scripting which I feel is a bit excessive just to detect an old tab. any other possible solutions?

This is for chrome extension development.

GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
  • "any other possible solutions?" - You could use chrome.storage.session to store the IDs of all new tabs. – Thomas Mueller Jan 11 '23 at 16:53
  • What's excessive in the scripting permission? It doesn't have a warning. I'd also argue that [automatic re-injection of content scripts on install/update](https://stackoverflow.com/q/10994324) is super convenient for the users in Chrome which doesn't do it automatically, unlike Firefox. – wOxxOm Jan 11 '23 at 19:00
  • @wOxxOm I didn't know that executeScript wouldn't show a warning... sounds like a good approach than – GorvGoyl Jan 12 '23 at 07:09
  • @ThomasMueller I didn't get that approach to detect old tab or special page.. would you mind explaining it more – GorvGoyl Jan 12 '23 at 07:10
  • @GorvGoyl - See the answer for an explanation. It's probably not exactly what you need, but maybe someone else can use it. – Thomas Mueller Jan 12 '23 at 18:47

1 Answers1

0

If you're only interested in distinguishing new tabs from tabs that are old and/or non-injectable, you can let the content scripts add the IDs of their tabs to session storage. Later on, you can look up the ID of any tab in session storage.

Tab IDs are only valid during the current session. When you store tab IDs in sessions storage, they are gone when you start a new session, which is what you want.

Content scripts don't know the ID of the tab they're running in, so they can't store it by calling chrome.storage.session.set() directly. However, content scripts can send a message to the service worker. The service worker receives information about the sender's tab along with the message.

The proof of concept below doesn't try to determine if a tab is injectable or not.

  • You can either do this by checking the tab's URL, e.g. if it starts with "chrome://" or "chrome-extension://". But I don't know if you can determine all non-injectable tabs like this, e.g. those whose URL is forbidden by the runtime_blocked_hosts policy.
  • Or you can inject an empty content script into the tab and check for errors. This requires the "scripting" permission, plus "activeTab" or the right host permissions, but lets you determine all non-injectable tabs.

When you click the action, the extension shows a notification. It tells you if the active tab is old, or if it's new and/or non-injectable.

manifest.json

{
    "manifest_version": 3,
    "name": "Tabs with vs without Content Scripts",
    "version": "1.0",
    "action": {
    },
    "background": {
        "service_worker": "background.js"
    },
    "content_scripts": [
        {
            "matches": ["*://*/*"],
            "js": ["content_script.js"]
        }
    ],
    "permissions": [
        "notifications",
        "storage"
    ]
}

background.js

async function action_on_clicked(tab) {
    let { [tab.id.toString()]: tab_id_stored } = await chrome.storage.session.get(tab.id.toString());
    let message;
    if (tab_id_stored === undefined) {
        /* Old or non-injectable tab */
        message = "Old or non-injectable tab";
    }
    else {
        message = "New tab";
    }
    chrome.notifications.create(
        {
            iconUrl: "/icon_128.png",
            message,
            title: "Tabs with vs without Content Scripts",
            type: "basic",
        },
        notificationId => {
            if (chrome.runtime.lastError === undefined) {
                console.log(notificationId);
            }
            else {
                console.error(chrome.runtime.lastError);
            }
        }
    );
}

function runtime_on_message(message, sender, sendResponse) {
    if (message == "store_tab_id") {
        if (sender.tab) {
            chrome.storage.session.set({ [sender.tab.id.toString()]: true })
            .then(() => {
                sendResponse("tab id stored");
            })
            .catch(error => {
                sendResponse(error);
            });
            return true;
        }
        else {
            sendResponse("sender.tab is undefined");
        }
    }
    else {
        sendResponse("unknown message");
    }
}

chrome.action.onClicked.addListener(action_on_clicked);
chrome.runtime.onMessage.addListener(runtime_on_message);

content_script.js

(async () => {
    let response = await chrome.runtime.sendMessage("store_tab_id");
    console.log("response", response);
})();
Thomas Mueller
  • 514
  • 1
  • 4
  • 10