How to check if a Firefox WebExtension is installed or not with page JavaScript?
Asked Answered
D

1

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.

Diggins answered 13/10, 2017 at 10:3 Comment(12)
Why the google-chrome-extension tag? Your question seems to be about Firefox.Tourney
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 websiteCompanion
@Companion That would not work naivelyCortez
Closing as duplicate of a canonical Chrome question; WebExtensions don't differ significantly enough from the Chrome model in this respect.Cortez
@Cortez 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.Diggins
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.Cortez
On the other hand, you do mention Firefox AddOn SDK, which is different from WebExtensions. Can you show your manifest?Cortez
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.Diggins
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.Cortez
Here's an FF specific sample: github.com/mdn/webextensions-examples/tree/master/…Cortez
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.Cortez
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.Cortez
C
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
      }
    
Cortez answered 13/10, 2017 at 12:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.