Emacs' browser-gt: claude's eyes and hands on the Web

https://melpa.org/packages/browser-gt-badge.svg

browser-gt was formely known as browsel.

Agents, like Claude, require eyes and hands to be able to help me accomplish work. While MCP servers can provide some of those capabilities, I find them too restrictive for this purpose. Instead, what about giving an agent the ability to read the DOM and execute JavaScript directly in the current browser's tab?

At the same time, I want these actions to be scriptable, so I can ask the agent to help me write commands that I can later execute myself whenever I need them.

Emacs can already be controlled programmatically through emacsclient. So why not give myself—and the agent—the ability to control the browser as well?

This was the motivation to create browser-gt. It creates a two-way bridge between Emacs and the browser: Emacs can query and control the browser, and the browser can ask Emacs to perform actions.

For example:

Extract all the h2 headings from the current Chrome tab and insert them into the current Emacs buffer.

But the interaction can go in the other direction too. From the browser, I can trigger Emacs commands to capture a selection in Org, save a page, save a ChatGPT conversation, or retrieve a YouTube transcript. browser-gt currently supports Chrome and Firefox.

It can also serve as a management tool. Its tab manager gives me an Emacs interface for seeing the many tabs I have open and quickly visiting, bookmarking, filtering, or closing them.

More generally, the goal is to make the browser scriptable from Emacs. Because the interface is programmable, the same operations can be used interactively by me, composed into Emacs Lisp commands, or invoked by an agent.

This is how to answer my question above, and the result of evaluating it while visiting the tab where this post is being displayed. Note it is an evaluation of javascript using browser-gt-js inside an emacs buffer using babel:

#+begin_src browser-gt-js :results raw
Array.from(document.querySelectorAll('h2'))
  .map(h => h.textContent.trim())
  .filter(t => t)
  .join('\n')
#+end_src

#+RESULTS:
Emacs' browser-gt: claude's eyes and hands on the Web

Its repository is https://github.com/dmgerman/browser-gt. Available via MELPA.

The summary is below:

2026-08-25-emacs_browser_gt/browser-gt-overview.png