Creating A Simple Firefox Addon

In the past I have written a couple of small extensions for chrome but never got a chance to write an extension for firefox. In the last couple of weeks, I tried to write one. Since I use firefox personally, I wanted to create something that would be useful for me.

There were two specific usecases that I could think of to write an extension.

Both of the applications are based on a simple principle,

Here is how I created it.

As you can see that there are two parts to it,

Firefox addon

Here is how I thought of the addon,

To implement this.

We need two specific things,


In this case manifest.json looks like

    "manifest_version": 2,
    "name": "remote-lib-bookmark",
    "version": "1.0",
    "description": "a simple firefox addon.",
    "icons": {
        "48": "icons/border-48.png"
    "content_scripts": [
            "matches": [
    "background": {
        "scripts": [
    "permissions": [

In this json file we are telling browser


The background.js looks like

// connect to the websocket server
var ws_con = new WebSocket("ws://localhost:8888/ws");


// set the call-back for onopen
ws_con.opopen = function(event){
	ws_con.send("hello from firefox addon");

// set the callback for onmessage
ws_con.onmessage = function (event){

// set the callback for onerror
ws_con.onerror = function(error){

// log the message that the addon has started.
console.log("remote-lib-bookmark addon started");

// create the context menu
  id: "trial-context",
  title: "remote-bookmark",
  contexts: ["page",  "browser_action", "page_action"]
}, function(e){console.log("menu created");});

// add the onClicked listener to the context menu.
browser.contextMenus.onClicked.addListener(function(info, tab) {

  // We receive the tab and the info about the clicked context here.

  // check which context menu has been clicked.
  switch (info.menuItemId) {
    case "trial-context":

      // get the page url and the title and send it to the we service (over web socket).
      var bookmark_data = {"title": tab.title, "url": info.pageUrl};

The web service

Since this is a web service running seperately, I chose to write it in python. I used tornado for writing it. Also since I wanted to try out leveldb this time, I used plyvel here.

The code for this looks like

import tornado.ioloop
import tornado.web
from tornado import websocket
import level_db_connect as ldb
import json

# handler for endpoint `/`
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        bookamrks = ldb.get_all_bookmarks()

# websocket handler for `/ws` endpoint
class EchoWebSocket(tornado.websocket.WebSocketHandler):
    def open(self):
        print("WebSocket opened")

    def on_message(self, message):
        print("received: ", message)
        self.write_message(u"You said: " + message)
        bookmark_data = json.loads(message)

    def on_close(self):
        print("WebSocket closed")

    def check_origin(self, origin):
        return True

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
        (r"/ws", EchoWebSocket),

if __name__ == "__main__":
    app = make_app()

The web service code is fairly simple, it is a modified version of the sample code of web socket demo on tornado’s docuentation

import plyvel
config = {}
def init_db():
    db = plyvel.DB('./db/', create_if_missing=True)
    config["db"] = db

def add_bookmark(bookmark_data):
    print("bookmark data", bookmark_data)
        bytes(bookmark_data["title"], "utf-8"),
        bytes(bookmark_data["url"], "utf-8"))

def get_all_bookmarks():
    bookmarks = {}
    for key, val in config["db"]:
        bookmarks[key.decode("utf-8")] = val.decode("utf-8")
    return bookmarks

At this point the service just receives the bookmark data over web socket and serves the json with all of the book marks at the end point /. This is a very crude implementation of both the firefox addon and the web service but I think it is good enough to give the reader a basic idea about the subject.

I also live streamed these coding sessions.

If you are interested, please have a look: