Tinkerer's bridge between Emacs and Firefox

Spookfox is a Firefox extension and an Emacs package, which allow Emacs and Firefox to communicate with each other. Its primary goal is to offer an Emacs tinkerer similar (to Emacs) framework to tinker their browser.

I use Spookfox as my daily driver to enable a number of workflow enhancements, e.g capturing articles I read and Youtube videos I watch.


There are 2 parts to install spookfox.

  1. Install the browser addon

    Download the addon (.xpi file) from releases page. Firefox will prompt you to install as soon as you download it.

    What is it not available on Firefox addons page?

    Because it is not approved on Firefox addons yet.

  2. Install Emacs package
    • Using straight.el

      (use-package spookfox
        (spookfox :type git
                  :host github
                  :repo "bitspook/spookfox"
                  :files ("lisp/*.el" "lisp/apps/*.el"))
    • Manually
      • Clone this repository

        git clone https://github.com/bitspook/spookfox <path-to-spookfox>
      • Add spookfox and its apps load-path

        (add-to-list 'load-path "<path-to-spookfox>/lisp")
        (add-to-list 'load-path "<path-to-spookfox>/lisp/apps")


Spookfox itself is a thin layer which provide websockets based communication between Emacs and Firefox. More functionality on top of it is provided with apps. Different apps need to be configured as documented in apps section below.

  1. Load the apps you want to use

    If you followed the installation instructions, all apps bundled with the package itself should be ready to be loaded with a call to require. For example, to load "spookfox-org-tabs" app, you'd write this Elisp:

    (require 'spookfox-org-tabs)
  2. Tell spookfox which apps you want to enable

    Provide the list of enabled apps to spookfox-enabled-apps variable:

    (setq spookfox-enabled-apps '(spookfox-org-tabs))
  3. Initialize spookfox

    Changes to spookfox-enabled-apps take effect when spookfox-init function is called. This function also starts the websockets server.



Spookfox has a modular architecture. An "app" is a bundle of functionality isolated and opt-in. Following apps come bundled with this package.


Basic access to browser's tabs.


  1. Access browser tabs in Elisp

    You can use this to enhance your Emacs usage. For example, check my Emacs config to see how I use it to more easily capture notes for articles I read in the browser.

  2. Open a browser tab, or start a new search in browser

    Command: open-new-tab

    Open a new tab in browser, or search for something using browser's default search engine (opens a new tab).

    PS you can use browse-url to achieve the same.


Manage browser's tabs in an org file (separate file or as a subtree in an existing one).


  1. Organize tabs freely in org file

    Tabs are stored as org-mode subtrees, which you are free to structure as you desire. You can group tabs by assigning org-mode tags, to manipulate tabs (open, close) in bulk.

  2. Chain tabs, so any changes to the tab in Firefox (e.g url change) are synced with the org-file
  3. Commands for manipulating tabs
    • spookfox-org-tabs-open-group

      Prompt for a tab group, and open all tabs belonging to that group.

    • spookfox-org-tabs-open

      Prompt user to select a tab and open it in spookfox browser.

    • spookfox-org-tabs-save-active-tab

      Save active tab in browser.

    • spookfox-org-tabs-save-all-tabs

      Save all currently open browser tabs at ‘spookfox-saved-tabs-target‘. It will open a capture buffer so user get a chance to preview and make changes.


  1. spookfox-saved-tabs-target

    spookfox-saved-tabs-target is an org-capture-templates target, where the browser tabs are saved. For example:

    ;; Store tabs in a file named =spookfox.org=, under '* Tabs' heading
    (setq spookfox-saved-tabs-target
            ,(expand-file-name "spookfox.org" org-directory)


Inject Javascript into any website open in your browser, and get the results back. I use it to help me take notes for Youtube videos with automatically added timestamp links.

  • Provided functions
    • spookfox-eval-js-in-active-tab

      spookfox-eval-js-in-active-tab is a byte-compiled Lisp function in ‘spookfox-js-injection.el’.

      (spookfox-eval-js-in-active-tab JS &optional JUST-THE-TIP-P)

      Evaluate JS in active firefox tab. Return value is a list of lists. Browser can have multiple active tabs (one per window). Every active tab can have multiple frames. If JUST-THE-TIP-P is non-nil, first tab’s first frame’s return value from the results is returned (instead of list of lists).

      JS is subjected to limitations of browser’s ability to execute it. It is similar to executing js in browser’s console. So for example running a script which declares a variable with ‘let‘ or ‘const‘ might cause the script to fail execution.

      Details about js execution: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript


  1. Write apps

    If you want to write apps for Spookfox to handle a use-case not covered by existing apps, for now you need to go through the source code to figure things out. I am still working on a web-accessible documentation for Spookfox. Code is allegedly well-commented and existing apps can act as good examples.

  2. Modify Spookfox

    To make changes on the Browser side of things, you'll have to modify and rebuild the browser addon itself. Unfortunately browsers don't allow injecting code into the running addon anymore (although it is possible to inject code into a website).

    Or you might want to fix a bug, or make the code cleaner.

    Please take a look at the contributing.org for setting up the development environment to hack Spookfox.

Related content

    No posts yet 😕