65

chrome.tabs returns undefined despite the fact I set tabs in the permissions block.

"permissions": [
    "tabs",
    "http://*/*",
    "https://*/*"
],
"content_scripts": [
    {
        "matches": [
            "http://*/*",
            "https://*/*"
        ],
        "js": [
            "js/myScript.js"
        ],
        "all_frames": true
    }
],

But in myScript.js, chrome.tabs is undefined.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Guy Korland
  • 9,139
  • 14
  • 59
  • 106
  • 9
    `chrome.tabs` is only available to code which runs in the extension's process, such as the background, options or popup page. Content scripts cannot access the `chrome.tabs` object. – Rob W Feb 22 '13 at 23:21
  • 4
    I have chrome.tabs inside a background page and it is undefined also – jstuardo Aug 27 '16 at 23:37

4 Answers4

103

Content script can only use chrome.i18n, chrome.dom, chrome.storage, and a subset of chrome.runtime/chrome.extension.

Most chrome APIs such as chrome.tabs are only available the background script (service worker in MV3), popup script, etc.

Solution

Pass a message from the content script to the background script and use the API there.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Raghvendra Parashar
  • 3,883
  • 1
  • 23
  • 36
  • 44
    It's a little confusing that the API docs for [content scripts](https://developer.chrome.com/extensions/content_scripts#pi) includes instructions about using the `chrome.tabs` API... – mgalgs Mar 07 '16 at 20:36
  • 7
    I'm vote down this, because I got absolute opposite doc from google official api docs. >chrome.tabs.getCurrent >Gets the tab that this script call is being made from. May be undefined if called from a non-tab context (for example: a background page or popup view). Please check this :https://developer.chrome.com/extensions/tabs#method-getCurrent – VicX Nov 29 '16 at 07:47
  • 2
    chrome.tabs is always undef for me – SuperUberDuper Jul 05 '17 at 10:19
  • 2
    This is simply not true. `chrome.tabs` is undefined in popup scripts. – claudekennilol May 22 '18 at 14:23
  • Just to add - I have tried using `debugger`s before `chrome.tabs` calls within a `background` page, and that's when I get `chrome.tabs` to be `undefined`. When I run that code without interruption, it seems to work fine (again, only within the `background` page) – Blundering Philosopher Nov 27 '18 at 10:17
  • 1
    @VicX you're right but the Chrome Developer documentation is frequently out of date or incorrect. This may be one of those cases. – mikemaccana Mar 21 '23 at 16:00
20

Content scripts have only limited access to Chrome APIs. This access does not include the API you are trying to use (e.g. chrome.tabs). If you need to use that API, you will have to do so in a background script1.

As listed in Chrome's content scripts documentation, the APIs available to a content script are [I have placed deprecated methods in strikethrough format]:

A couple of the listed APIs are deprecated and have been for some time. Those that are deprecated have moved to different locations (also listed above):

While not officially deprecated, extension.lastError is also available as runtime.lastError. At this point, it is usually referred to at that location:

Partition your extension into background scripts and content scripts

You are going to need to separate your code into what needs to be in a background script and what needs to be in content scripts, based on the capabilities available to each type of script. Content scripts have access to the DOM of the web page into which they are injected, but limited access to extension APIs. Background scripts have full access to the extension APIs, but no access to web page content. You should read the Chrome extension overview, and the pages linked from there, to get a feel for what functionality should be located in which type of script.

It is common to need to communicate between your content scripts and background scripts. To do so you can use message passing. This allows you to communicate information between the two scripts to accomplish things which are not possible using only one type of script. For instance, in your content script, you may need information which is only available from one of the other Chrome APIs, or you need something to happen which can most appropriately (or only) be done through one of the other Chrome extension APIs. In these cases, you will need to send a message to your background script, using chrome.runtime.sendMessage(), to tell it what needs to be done, while providing enough informaiton for it to be able to do so. Your background script can then return the desired information, if any, to your content script. Alternately, you will have times when the processing will primarily be done in the background script. The background script may inject a content script, or just message an already injected script, to obtain information from a page, or make changes to the web page.


  1. Background script means any script that is in the background context. In addition to actual background scripts, this includes popups and options pages, etc. However, the only page that you can be sure to have consistently available to receive messages from a content script are your actual background scripts defined in manifest.json. Other pages may be available at some times as a result of the user's interaction with the browser, but they are not available consistently.

This answer was moved from a duplicate question, and then modified.

Community
  • 1
  • 1
Makyen
  • 31,849
  • 12
  • 86
  • 121
  • 1
    getCurrent chrome.tabs.getCurrent(function callback) *Gets the tab that this script call is being made from.* May be undefined if called from a non-tab context (for example, a background page or popup view). https://developer.chrome.com/extensions/tabs#method-getCurrent – Greg Domjan Mar 20 '19 at 10:26
  • 2
    @GregDomjan `chrome.tabs` is only available in the background context. Content scripts are not in the background context and don't have `chrome.tabs` available. It's possible to open HTML pages that are in your extension within a tab. The most common is options pages, but you can have others. These will be in the background context and have a tab associated with them, which can be obtained from [`chrome.tabs.getCurrent()`](https://developer.chrome.com/extensions/tabs#method-getCurrent). – Makyen Mar 21 '19 at 19:00
1

https://developer.chrome.com/extensions/tabs#method-getSelected shows

getSelected

chrome.tabs.getSelected(integer windowId, function callback)
Deprecated since Chrome 33. Please use tabs.query {active: true}.
Gets the tab that is selected in the specified window.

Maybe, you should use chrome.tabs.query in popup.js like this

chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
    console.log(tabs[0].url);
});

, reload your extension and check the result in the inspect element of your extension.

result image

code image

https://developer.chrome.com/extensions/tabs#type-Tab shows that The URL the tab is displaying. This property is only present if the extension's manifest includes the "tabs" permission.(Just for remind someone forgot. I was forgot it when I just test it.)

  • 10
    No, the problem is that tabs API is **totally unavailable from injected content script**. – oxfn Mar 13 '19 at 19:29
-3

Check this answer also https://stackoverflow.com/a/6718277/449345 This one worked for me

chrome.tabs.getSelected(null, function(tab){
    console.log(tab);
});
Community
  • 1
  • 1
chestozo
  • 1,203
  • 1
  • 12
  • 29