Add-ons using the techniques described in this document are considered a legacy technology in Firefox. Don't use these techniques to develop new add-ons. Use WebExtensions instead. If you maintain an add-on which uses the techniques described here, consider migrating it to use WebExtensions.

From Firefox 53 onwards, no new legacy add-ons will be accepted on (AMO).

From Firefox 57 onwards, WebExtensions will be the only supported extension type, and Firefox will not load other types.

Even before Firefox 57, changes coming up in the Firefox platform will break many legacy extensions. These changes include multiprocess Firefox (e10s), sandboxing, and multiple content processes. Legacy extensions that are affected by these changes should migrate to WebExtensions if they can. See the "Compatibility Milestones" document for more.

A wiki page containing resources, migration paths, office hours, and more, is available to help developers transition to the new technologies.

This page contains small, self-explanatory code snippets.

System info

Operating system detection

// Returns "WINNT" on Windows Vista, XP, 2000, and NT systems;
// "Linux" on GNU/Linux; and "Darwin" on Mac OS X.
var osString = Services.appinfo.OS;

Detecting the host application and version

// Get the name of the application running us; // Returns "Firefox" for Firefox
Services.appinfo.version; // Returns "" for Firefox version

Retrieving the version of an extension as specified in the extension's install.rdf

AddonManager.getAddonByID("", function(addon) {
  // This is an asynchronous callback function that might not be called immediately
  alert("My extension's version is " + addon.version);

Restarting Firefox/Thunderbird/SeaMonkey_2.0

bug 338039 tracks improving this situation by providing a simple method to restart the application.

Example for Firefox:


Mouse and keyboard

Detecting mouse wheel events

When scrolling the mouse wheel on an element, the DOMMouseScroll event fires. event.detail contains the number of lines to scroll. This event is Mozilla-only; other browsers may support window.onmousewheel.

<div id="scrollArea" style="overflow: scroll; height: 6em; width: 10em;">
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.
  This is the scrolling area.

<script type="text/javascript">
  var elm = document.getElementById("scrollArea");
  elm.addEventListener("DOMMouseScroll", function scroll(event){
    //event.detail is positive for a downward scroll, negative for an upward scroll
    alert("scrolling " + event.detail + " lines");
  }, false);

If you do not receive a DOMMouseScroll event while holding any of the modifier keys (Ctrl,Shift,Alt,Meta) you should check the mousewheel.withcontrolkey.action and related preferences. The meaning of the action preference is shown in the following table

mousewheel.withXXXkey.action Result
0 Scroll by lines. If set, you will receive DOMMouseScroll events.
1 Scroll by page.
2 Move around in the history. If set, you will not receive DOMMouseScroll events.
3 Change text size. If set, you will not receive DOMMouseScroll events.

You can listen to mouse wheel click events just like normal click events (via mousedown and mouseup events). When the mouse wheel is clicked, event.button will be equal to 1.

Simulating mouse and key events

Also, new in Firefox 3 / Gecko 1.9:

var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
utils.sendMouseEvent("mousedown", 10, 10, 0, 1, 0);
utils.sendMouseEvent("mouseup", 10, 10, 0, 1, 0);

Getting the currently selected text

From browser.xul overlay context:

var selectedText = document.commandDispatcher.focusedWindow.getSelection().toString();


content.getSelection(); // |window| object is implied; i.e., window.content.getSelection()


getBrowserSelection(); // |window| object is implied; i.e., window.getBrowserSelection()

This final option massages the selection to remove leading and trailing whitespace. It also collapses consecutive whitespaces into a single whitespace, and returns at most 150 characters, making it ideal to display text in context menus. It is defined at Note that it returns the empty string (""), not false, when nothing is selected. getBrowserSelection() is not implemented on some platforms, such as Thunderbird and Songbird.

See also

Discovering which element in the loaded document has focus

// focusedControl stores the focused field, or null if there is none.
// This excludes textareas for simplicity, but onPageLoad() can easily be
// modified to cycle through textareas as well. Further enhancements would include
// handling for fields dynamically added to the page (e.g., by page javascript).

var focusedControl;

window.addEventListener("load", function(e) { onWindowLoad(e); }, false);

function onWindowLoad() {
  gBrowser.addEventListener("load", onPageLoad, true);

function onPageLoad() {
  pageDoc = document.commandDispatcher.focusedWindow.document;
  var inputList = pageDoc.getElementsByTagName('input');
  for (var i=1; i<inputList.length; i++) {
    addEventListener("focus", function(e) {onFocusInput(e);}, false);
    addEventListener("blur", function(e) {onBlurInput(e);}, false);

function onFocusInput(focusEvent) {
  focusedControl = focusEvent.originalTarget;

function onBlurInput(blurEvent) {
  focusedControl = null;


var element = document.commandDispatcher.focusedElement;

Inserting text at the cursor

function insertText(element, snippet)
  var selectionEnd = element.selectionStart + snippet.length;
  var currentValue = element.value;

  var beforeText = currentValue.substring(0, element.selectionStart);
  var afterText = currentValue.substring(element.selectionEnd, currentValue.length);

  element.value = beforeText + snippet + afterText;

  //put the cursor after the inserted text
  element.setSelectionRange(selectionEnd, selectionEnd);

insertText(document.getElementById("example"), "the text to be inserted");

Disabling JavaScript programmatically

// Disable JS in the currently active tab from the context of browser.xul
gBrowser.docShell.allowJavascript = false;

If this isn't your browser, you should save the value and restore it when finished. If you wish to block selected scripts based on their URI, implement nsIContentPolicy.

Using string bundles from JavaScript

Assuming the extension has with name/value pairs such as:

 invalid.url=The speficied URL, %S, is invalid. That was attempt number %S.

These properties can be accessed from JavaScript in the following manner:

 var common = {

  _bundle: Components.classes[";1"]

           getLocalizedMessage: function(msg) {
              return this._bundle.GetStringFromName(msg);


Another similar alternative (using both GetStringFromName and formatStringFromName), is:

var fcBundle = Components.classes[";1"]

function getStr(msg, args){ //get localised message
  if (args){
    args =, 1);
    return fcBundle.formatStringFromName(msg,args,args.length);
  } else {
    return fcBundle.GetStringFromName(msg);

/* Usage */
alert(getStr("invalid.url", "http://bad/url/", "3")); //for message with parameters
alert(getStr("invalid.url")); //for message without parameters

Getting postData of a webpage

First, you need to get the browser you want, and its historySession.

var Ci = Components.interfaces;
var Cc = Components.classes;

//assume you can not get the main window object directly, if you can, just use it
var wm = Cc[";1"].getService(Ci.nsIWindowMediator);
var mainWindow = wm.getMostRecentWindow("navigator:browser");

//get sessionHistory from the current selected tab
var history = mainWindow.gBrowser.selectedBrowser.webNavigation.sessionHistory;

And then get the page you want, and it's postData. This example obtains the post data of the last page.

var postdata = history.getEntryAtIndex(history.index-1,false).QueryInterface(Ci.nsISHEntry).postData;

If you got here all by yourself, your problem must be at reading the postData, because it's a nsIInputStream object, whose available function always returns 0. And if you read it directly, you always got nothing. And here's how it's done

postdata.QueryInterface(Ci.nsISeekableStream).seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
var stream = Cc[";1"].createInstance(Ci.nsIBinaryInputStream);
var postBytes = stream.readByteArray(stream.available());
var poststr = String.fromCharCode.apply(null, postBytes);

//Do anything to your poststr

Getting a string from the input stream is made somewhat simpler in Firefox 4, by the addition of NetUtil.readInputStreamToString()

Getting postData of a request before the request is sent

The above code will get the postdata for a page that has already loaded. To see what the postdata looks like before the request is even sent, use the 'http-on-modify-request' observer topic:

observerService.addObserver(observer, 'http-on-modify-request', false);

where "observer" is an object that has a method "observe":

function observe(subject, topic, data) {
  postData = subject.uploadStream;

Here again, postData is not a string, but an nsIInputStream, so you can use the last code snippet of the previous section to get the data as a string. However, if you are not going to cancel the request, you need to "rewind" it by calling:

postdata.QueryInterface(Ci.nsISeekableStream).seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);

Adding custom certificates to a XULRunner application

You need to ship a XULRunner application with your own SSL certificates? For Firefox, you could use the Client Customization Kit (CCK) to create an extension that does exactly that. To get the same feature for your XULRunner application, follow those steps:

First, put the certificates you want to ship into the content/certs folder of your application.

Then create a XPCOM service that adds the certificates inside that directory to the certs database on application startup. Put this code in the components/certsService.js file:

const Cc = Components.classes;
const Ci = Components.interfaces;


const gObserver = Cc[';1'].getService(Ci.nsIObserverService);
const gIOService = Cc[";1"].getService(Ci.nsIIOService);

function CertsService() {}

CertsService.prototype = {
    observe: function(aSubject, aTopic, aData) {
        switch(aTopic) {
            case "app-startup":
            case "xpcom-shutdown":
            case "final-ui-startup":

    init: function() {
      // add all certificates you want to install here (or read this from your prefs.js ...)
      var certificates = "root.crt,user.crt";

      var certs = certificates.split(',');
      for (var i=0; i<certs.length; i++) {
        this.addCertificate(certs[i], 'C,c,c');

    addCertificate: function(CertName, CertTrust) {
      var certDB = Cc[";1"].getService(Ci.nsIX509CertDB2);
      var scriptableStream=Cc[";1"].getService(Ci.nsIScriptableInputStream);
      var channel = gIOService.newChannel("chrome://YOURAPP/content/certs" + CertName, null, null);
      var beginCert = "-----BEGIN CERTIFICATE-----";
      var endCert = "-----END CERTIFICATE-----";

      certfile = certfile.replace(/[\r\n]/g, "");
      var begin = certfile.indexOf(beginCert);
      var end = certfile.indexOf(endCert);
      var cert = certfile.substring(begin + beginCert.length, end);
      certDB.addCertFromBase64(cert, CertTrust, "");

    classDescription: "Certificate Service",
    contractID: ";2",
    classID: Components.ID("{e9d2d37c-bf25-4e37-82a1-16b8fa089939}"),
    QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
    _xpcom_categories: [{
        category: "app-startup",
        service: true

function NSGetModule(compMgr, fileSpec) {
    return XPCOMUtils.generateModule([CertsService]);

You need to delete your existing profile, otherwise the XPCOM service is not used. See How to Build an XPCOM Component in Javascript for details. Now are your certificates installed on every application startup. Unfortunately that seems to be the only working solution, apart from modifying the Mozilla source code and recompiling.

Generating Random Bytes

Useful snippet for generating random bytes that can, for example be used as a good source for cryptographic entropy.

const NOB = 128; // number of bytes
var buffer = '';
var prng = Components.classes[';1'];
var bytebucket =  prng.getService(Components.interfaces.nsIRandomGenerator).generateRandomBytes(NOB, buffer);

Detecting full screen mode on/off

It works for that global 'window' object at least.

window.addEventListener('fullscreen', function(){
  alert('fullscreen mode on or off')
}, false)

Getting addon install path

First one using addon manager:

AddonManager.getAddonById('example@addon', function(addon) {
  let path = addon.getResourceURI().path;
  // something like /home/username/....

example@addon is extension id.

Another one is to utilize bootstrap.js startup function data argument:

function startup(data, reason) {
  // some code ...
  // some code ...