6

I have developed a WebExtension for Firefox and my website works with the extension as a prerequisite. I need to check programmatically whether the extension is installed or not and if not ask the user to install it.

I am not able to find a way how to check this operation of whether my extension is already installed in the user's browser.

Editor note: Methods available in Firefox differ from those available in Chrome, so this question is not a duplicate.

Xan
  • 74,770
  • 16
  • 179
  • 206
Maninder
  • 1,261
  • 5
  • 20
  • 34
  • Why the google-chrome-extension tag? Your question seems to be about Firefox. – Filnor Oct 13 '17 at 10:05
  • I believe your extension can add a global variable to the page. Add a very specifically named global variable and, in your page, check if it exists. Something like `window.my-ext-name-a1b2c34d = true` in your extention, and then check `if (window.my-ext-name-a1b2c34d)` on your website – TKoL Oct 13 '17 at 10:09
  • @TKoL That would not work naively – Xan Oct 13 '17 at 10:17
  • 1
    Closing as duplicate of a canonical Chrome question; WebExtensions don't differ significantly enough from the Chrome model in this respect. – Xan Oct 13 '17 at 10:18
  • @Xan This question is not duplicate to Chrome. There are ways for chrome to check if an extension is installed or not. I am interested in this type of check for FIREFOX. – Maninder Oct 13 '17 at 10:52
  • 1
    Are you aware that, with exception of small differences, Firefox extensions behave the same way? All of the answers (at least highly voted ones) apply. And I don't think there's a mechanism available only in Firefox. – Xan Oct 13 '17 at 10:54
  • On the other hand, you do mention Firefox AddOn SDK, which is different from WebExtensions. Can you show your manifest? – Xan Oct 13 '17 at 10:56
  • Firefox add on SDK , I added by mistake. I know both chrome and FF follow web extensions api. I am not talking about developing a FF extension. The question is to find ways to detect an extension. Pretty clear. – Maninder Oct 13 '17 at 11:25
  • Indeed. Pretty clear. You'll need to implement changes to your extensions to make it cooperate with the webpage. As I said, everything in the linked question applies, and I am unaware of any radically different methods specific to FF. Still a duplicate. – Xan Oct 13 '17 at 11:26
  • Here's an FF specific sample: https://github.com/mdn/webextensions-examples/tree/master/page-to-extension-messaging – Xan Oct 13 '17 at 11:34
  • You know what, I'll reopen this. Simply because possibilities in FF are smaller than in Chrome (I didn't know it doesn't currently support `externally_connectable`), it's worth noting it here. – Xan Oct 13 '17 at 11:38
  • Okay, @Maninder, there's no shame in admitting wrongs. I looked more deeply into it and Firefox is _shockingly_ different from Chrome in this regard. Thanks for actually bringing this question up, even though it would probably be helpful if you mentioned that some methods don't work. – Xan Oct 13 '17 at 11:50

1 Answers1

9

Important note to begin with: A page can't query if an extension is installed without explicit help from the extension. This is done to prevent browser fingerprinting and/or preventing sites from denying content if certain extensions are installed.

WebExtensions are largely built upon the same principles as Chrome extensions. As such, this question is relevant: Check whether user has a Chrome extension installed.

However, some of the best methods available in Chrome are currently unavailable in Firefox:

The files will then be available using a URL like:

moz-extension://<random-UUID>/<path/to/resource>

This UUID is randomly generated for every browser instance and is not your extension's ID. This prevents websites from fingerprinting the extensions a user has installed.

As such, what are your options? The page can't talk directly to the extension context (background), and the background can't directly affect the page; you need a Content script to interact with the page content.

How can page code and a content script communicate? They are isolated from each other unless content script does something about it.

First off, generic tricks that work in both FF and Chrome:

  • You can create or modify a DOM element on the page from a content script and look for those modifications in the page.

      // Content script
      let beacon = document.createElement("div");
      beacon.classname = browser.runtime.id;
      document.body.appendChild(beacon);
    
      // Page script
      // Make sure this runs after the extension code
      if (document.getElementsByClassName("expected-extension-id").length) {
        // Installed
      } else {
        // Not installed
      }
    
  • You can use postMessage to communicate between contexts, though it's clunky to use as a bidirectional channel.

    Here's documentation and sample WebExtension.

      // Content script code
      window.postMessage({
        direction: "from-content-script",
        message: "Message from extension"
      }, "*");
    
      // Page code
      window.addEventListener("message", function(event) {
        if (event.source == window &&
            event.data.direction &&
            event.data.direction == "from-content-script") {
          // Assume extension is now installed
        }
      });
    
  • You can use custom DOM events in a similar way.

There are interesting Firefox-specific approaches as well:

  • You can share code with the page using exportFunction or cloneInto:

      // Content script
      function usefulFunction() {
        /* ... */
      }
    
      const extensionInterface = {
        usefulFunction
      }
      window.wrappedJSObject.extensionInterface = 
        cloneInto(extensionInterface, window, {cloneFunctions: true});
    
      // Page code
      if (typeof window.extensionInterface !== "undefined") {
        // Installed
        window.extensionInterface.usefulFunction();
      } else {
        // Not installed
      }
    
Xan
  • 74,770
  • 16
  • 179
  • 206