How to detect if a Chrome extension is installed

NOV 20 2012

Yesterday I added a one click installer for my TweetDeck trends column extension. It requires Chrome's Tampermonkey extension to work, so I wanted to check if Tampermonkey was installed, before enabling the install button.

Detecting whether or not an extension is installed when you do not own that extension, (if you own the extension, it's easy) has become a bit of an arms race. Google don't really like you doing it, but developers find a way, which Google eventually prevent.

But here's a method that works as of writing, November 2012.

Firstly download the extension you wish to detect, and look at its manifest.json file. This can be done by going to chrome-extension://[[extension's ID here]]/manifest.json. You can get the extension's ID by going to chrome://chrome/extensions/ and ticking the Developer mode checkbox, on the top right of that page.

For Tampermonkey, the extension ID is dhdgffkkebhmkfjojejmpbldmpobfkfo.

Below, an extract of chrome-extension://dhdgffkkebhmkfjojejmpbldmpobfkfo/manifest.json

   "name": "Tampermonkey",
   "options_page": "options.html",
   "permissions": [ "notifications", "unlimited_storage", "tabs", "management", "webNavigation", "webRequest", "webRequestBlocking", "\u003Call_urls\u003E" ],
   "update_url": "http://clients2.google.com/service/update2/crx",
   "version": "2.7.2890",
   "web_accessible_resources": [ "emulation.js", "environment.js" ]
}

The last line is the line we're interested in; web_accessible_resources. These are the files we can detect externally, and hence, knowing the extension's ID, and the name of one of these files, we can detect that the extension has been installed.

In code below, we are essentially pinging the file to check if it exists (requesting only the file headers and checking HTTP status code 200). This should be very quick, as protocol chrome-extension:// is essentially file:/// and we are not fetching possibly bulky file content.

function detectChromeExtension(extensionId, accesibleResource, callback){
    if (typeof(chrome) !== 'undefined'){
        var xmlHttp = new XMLHttpRequest(),
            testUrl = 'chrome-extension://' +extensionId +'/' +accesibleResource;
        xmlHttp.open('HEAD', testUrl, true);
        xmlHttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        xmlHttp.timeout = 1000;

        xmlHttp.onreadystatechange = function() {
            if (xmlHttp.readyState == 4 && typeof(callback) == 'function') {
                if (xmlHttp.status == 200) {
                    callback.call(this, true);
                } else {
                    callback.call(this, false);
                }
            }
        }        
        xmlHttp.ontimeout = function() {
            if (typeof(callback) == 'function')
                callback.call(this, false);
        }        
        xmlHttp.send();
    } else {
        if (typeof(callback) == 'function')
            callback.call(this, false);
    }    
};
// Example call
detectChromeExtension('dhdgffkkebhmkfjojejmpbldmpobfkfo', 'emulation.js', myCallbackFunction);

Or in jQuery

$.detectChromeExtension = function(extensionId, accesibleResource, callback){
    if (typeof(chrome) !== 'undefined'){
        var testUrl = 'chrome-extension://' +extensionId +'/' +accesibleResource;
        $.ajax({
            url: testUrl,
            timeout: 1000,
            type: 'HEAD',
            success: function(){
                if (typeof(callback) == 'function')
                    callback.call(this, true);
            },
            error: function(){                
                if (typeof(callback) == 'function')
                    callback.call(this, false);
            }
        });
    } else {
        if (typeof(callback) == 'function')
            callback.call(this, false);
    }
};
// Example call
$.detectChromeExtension('dhdgffkkebhmkfjojejmpbldmpobfkfo', 'emulation.js', myCallbackFunction);

Where myCallbackFunction performs an action, based on the boolean argument supplied to the function.

function myCallbackFunction(extensionExists) {
    if (extensionExists) {
        console.log('Extension present');
    } else {
        console.log('Extension not present');
    }
}

Comments

I've tried with IE tab extension. Sample code as below:
detectChromeExtension('hehijbfgiekmjfkfjpbkbammjbdenadd', 'manifest.json', myCallbackFunction);

But it always return False. Have u ever met this issue, please help me.
Thanks

Are there any other web accessible resources, apart from manifest.json that you can use? As you can see above, I'm using a file called emulation.js