How to detect if a Chrome extension is installed

March 01, 2018
Written by
Phil Nash
Twilion

In other posts we have investigated how to capture screen output in Chrome and built a screen sharing video chat application. There was one feature missing though. The Chrome extension made screen capture possible, but didn’t test whether it  had been installed before the application tried to use it. In this post we are going to build a Chrome extension that can be detected from the front end.

Getting set up

We’re going to use the extension we built for screen capture and add the functionality to make it detectable. We’ll then build an example to show handling the two cases, with and without the extension.

Download the source for the extension from the GitHub repo or by cloning the building-extension-detection branch

git clone -b building-extension-detection https://github.com/philnash/screen-capture.git
cd screen-capture

The extension

Open extension/extension.js and take a look at line 1.

chrome.runtime.onMessageExternal.addListener(

This code lets us listen for messages sent from web pages to the extension. The code to send a message from a web page looks like:

chrome.runtime.sendMessage(EXTENSION_ID, request, (response) => { })

A web page can send a message to a specific extension by calling the sendMessage function providing the extension ID, an object as a request and a callback function which has a response parameter. This response parameter is what we will use to detect whether the extension is present.

We can do this because in Chrome sending a message to an extension that is not there will result in the callback being executed with null as the response parameter.. Our app can test for that null value and decide whether to continue with the rest of the screen capture flow or not.

Note: If you are working with an extension that does not use a background page then you will need to add one. You’ll need these lines in your manifest.json and a background script that listens for incoming messages using the chrome.runtime.onMessageExternal.addListener( function, like the example project’s extension.js.

Responding to messages

The extension is already responding to messages, however it currently only responds to a single type and only with a stream of the user selected screen. In order to detect the extension we need to be able to send back a simpler message. That message could just be a boolean, but to be more useful for the future, we will reach into our extension manifest and return the current version of the extension.

Add the following code to the top of extension.js

 

chrome.runtime.onMessageExternal.addListener(
  (message, sender, sendResponse) => {
    if (message == 'version') {
      const manifest = chrome.runtime.getManifest();
      sendResponse({
        type: 'success',
        version: manifest.version
      });
      return true;
    }
    const sources = message.sources;
    const tab = sender.tab;
    chrome.desktopCapture.chooseDesktopMedia(sources, tab, streamId => {
      // result of selecting desktop
    });
    return true;
  }
);

 

Now when sent the message "version",  the extension will respond with the current version.

Open the Chrome extensions settings (chrome://extensions) and upload or reload the extension, taking note of the ID. Let’s see how to use this from the page now.

Detecting the extension from the page

Let’s update the Chrome screen capture example to check for the extension. Open up chrome/index.html from the repo. First, hide the “Get the screen” button so that no-one tries to interact with it when we don’t know if it will work or not.

 

  <video autoplay id="screen-view" width="50%"></video>
  <button id="get-screen" style="display:none">Get the screen</button>
  <button id="stop-screen" style="display:none">Stop the screen</button>

When the page loads we are going to send the message "version" to the extension to see if it is present. If the extension returns its version we will unhide the button and set up the click listener. Don’t forget to fill in the extension ID with your own.

    (() => {
      const EXTENSION_ID = 'YOUR_EXTENSION_ID_HERE';

      chrome.runtime.sendMessage(EXTENSION_ID, 'version', response => {
        if (!response) {
          console.log('No extension');
          return;
        }
        console.log('Extension version: ', response.version);
        const video = document.getElementById('screen-view');
        const getScreen = document.getElementById('get-screen');
        const stopScreen = document.getElementById('stop-screen');
        const request = { sources: ['window', 'screen', 'tab'] };
        let stream;

        getScreen.style.display = 'inline';
        getScreen.addEventListener('click', event => {
          // code to capture the screen and add to the video element
        });

        stopScreen.addEventListener('click', event => {
          // code to stop the screen capture
        });
      });
    })();

Test this out by serving chrome/index.html over localhost (I use serve for this) and opening the page in Chrome. The extension is currently installed and enabled so the “Get the screen” button will appear the current extension version will be logged in the console.

Disable the extension from the Chrome extensions settings (chrome://extensions) and reload the page. This time, the button will not appear and the console log will read “No extension”.

Extension detection completion

If you want to build an application with screen capture in Chrome, you need to use an extension. Now you know how to build an extension that can be detected so that the feature is only enabled when the extension is present. To improve on this, you can trigger an inline installation of your extension if it’s not available only when a user needs it.

The full code is available in the master branch of the GitHub repo.

Please note, you do need to know the ID of the extension and set it to be externally connectable from the domain on which the extension is needed. This means that this technique is unlikely to work for third party extensions, it is solely useful for detecting your own extension.

Got questions about this? Drop them in the comments below or let me know on Twitter at @philnash.