Web browsing in Emacs
Why would you want web browsing in a text editor?
Emacs has a tendency to try and absorb all user-facing interactions I have with a computer. Some people seem able to separate “Emacs stuff” — like programming or using org-mode for note taking — but Emacs’ extendability makes me want to use it for everything. For a long time I have only really needed four different tools to do any kind of work at a computer:
- GNU Emacs (with my personal config).
- Tailscale to connect to my other machines.
- Syncthing so that I have local access to my files1.
- A web browser (usually Firefox).
Quickly getting these four things up and running is usually my first priority when setting up a new machine, and they require different amounts of work. Critically Firefox requires a GUI environment in order to run, but it’s really quite unnecessary to get a desktop environment or tiling window manager up and running — and dealing with their conflicting keybinds — when all I’m going to be doing is working in Emacs perhaps 80% of the time, finding information or reading docs in Firefox 15% of the time, and using a stray terminal the remaining 5% (something I can easily replace with one of Emacs’ many terminal and shell solutions). This is why I like using exwm
2. Rather than using Emacs’ window manager capabilities to manage all your X windows it allows you to stay continually within Emacs and just treat any stray non-Emacs GUI programs within the same system. The solution then seems to try and subsume web browsing into my preëxisting workflow. There are many solutions to this, but I prefer ones that work with text as the primary medium as that is what Emacs is best oriented to work with.
The Emacs Web Wowser (eww)
eww
is probably the most well-known of Emacs’ web browsing solutions, chiefly because it comes included with it. It is also the one I have the most experience with. I first came across eww
as a consequence of reading about all of the crazy features included in Emacs by default like Tetris and Gnus. This isn’t very surprising; web browsers are some of the largest ubiquitous user-facing applications, so the fact that Emacs ships with one as a tangential feature is very surprising. However, these visions of browsing the web are often quickly crushed when one uses eww
for the first time. It does not load any CSS, so websites do not look like one is accustomed to, and a lot of javascript functionality is non-functional.
I expect this experience — or at least something like it — to be somewhat universal amongst those who have even tried using eww
. The modern web is built around these technologies, and going without them might seem almost impossible. But there is a place for eww
in a modern workflow. The strength of Emacs is its power for working with text, and most media I interact with in a web browser is text. Emacs then is really the perfect environment for this. Reading and rewriting the content of web pages side-by-side using the same key-chords and user-interface allows for minimal context friction. But there are serious downsides, primarily ugly formatted headers and images. Most of the time eww
can figure out the main readable content using the eww-readable
function, bound to R
by default. It’s meant to strip out long “navigation menus and the like”. In my experience it is either hit or miss. For some web pages like wikipedia it seems to work well (but only for some pages), but for others like github it just strips out the entire page. Thankfully it is bound to a convenient key and its easy to switch between the two views quickly. Images are probably one of the first things that stops people from using eww
, with large ones causing the site to jump around as they cover the whole screen and then disappear. I solved this using ultra-scroll, which provides scrolling smoother than you could ever imagine in Emacs. It also allows you to scroll intuitively over images, rendering them as you would expect in a traditional browser like Firefox. With a slow network connection eww
can have some problems with blocking, but this can be remedied by setting eww-retrieve-command
:
(setq eww-retrieve-command '("chromium" "--headless" "--dump-dom"))
eww
is written by Lars Ingebrigtsen of gnus
fame. It uses the shr
(simple HTML Renderer) program written in elisp to render HTML. He originally wrote shr
to read elfeed
entries in Emacs and eww
is merely the addition of browsing (or wowsing) capability built on top of it. shr
’s elisp nature is why it can sometimes struggle with complicated site layouts, but in my experience it is usually fast enough, especially with native compilation.
Generally eww
can be surprisingly powerful, but most of its power (like Emacs itself) comes from its tight integration with other tooling and extensibility with elisp, rather than any amazing workflow it has built for you in advance. There is very little to learn, but a lot to master.
w3m
w3m
can some sense be seen as the “hardcore” version of text-based web browsing in Emacs. w3m
relies on the eponymous TUI program to render web pages in a way similar to Lynx, allegedly the world’s oldest continually-maintained web browser. w3m
even comes with lynx bindings by default, although you can also change them to the included “info-like” ones. It allows for tabs, bookmarks, and other features one would expect in a modern browser. It also relies on interpreting the raw HTML to format the page, rather than rendering CSS. Like eww
it also does not support javascript. Like I alluded to earlier, this is both a blessing and a curse, and reading just straight text can be very nice, both from a therapeutic minimalist way and a way to minimize context-switching. It is also nice and async by default, since it uses an external binary to fetch websites, not that it takes very long to load to begin with since it’s not running any heavy javascript. One nice difference between w3m
and eww
is also that the arrow keys navigate to the next link in the page by default, and the text in the buffer will resize itself whenever the buffer is resized3, something that is very handy if you’re using a package like golden-ratio that resizes windows depending on focus.
Non-text based
While I prefer text-based browsers that fit more seamlessly into the rest of Emacs, there are other solutions for more traditional browser experiences.
Xwidgets
Since version 25 Emacs has had the ability to be compiled with xwidgets support, and to render complete web pages through webkit. To do this merely add the --with-xwidgets
flag to Emacs when compiling, and then run M-x xwidget-webkit-browse-url
to surf the web! Sadly this doesn’t work very well at the moment, as you’ll quickly realize if you were to do the above. There is apparently a bug in the xwidget library webkitgtk
that causes Emacs to abort. Worse yet its status is wontfix
since GNU Emacs seems to be the only program affected by it thanks to its old and strange ways of doing things. Upon crashing Emacs links to a 22 year old bug report that had its last message sent five years ago, so I’m not exactly holding out hope (but maybe a good project to work on for someone?). It seems to work with version 2.40 of webkitgtk
so try and use that if you’re having issues. Sadly I have not gotten it to work but I keep seeing people mentioning xwidgets as an option so it might work on some machines.
EAF
Getting a non-text browser in the text-based environment of Emacs requires working around Emacs’ systems. EAF (Emacs Application Framework) does this through creating an exterior python system that then hooks into Emacs to run a number of programs, chief among them a webkit-based browser.
The largest problem I have with the EAF’s browser is not really with the browser itself, although it is a bit unstable, but instead with the EAF itself. Being part of this large group of packages that feel very external to Emacs they are troublesome to install and maintain as part of a workflow. Installing EAF (something you’re probably only doing for the browser) asks you individually if you’d like to install things like a git client, system monitor, file browser, terminal, multiple demos, and numerous other things. Some of these things are impressive and useful, but I’d rather explicitly say what I’d like to install instead of having a Y/N on each program. Imagine having to do that for every ELPA package when first launching Emacs! EAF is of course nowhere near that level, but it’s still a baffling design decision. It also makes it way less portable, since I can’t describe what EAF programs I want to install (although I can for which ones I want to use) in a declarative way. It also has a few issues with javascript that feel like deal-breakers for a graphical browser, I’d rather go all-the-way with a text-based browser like eww
or use a fully functional graphical browser like firefox.
Footnotes:
I can use tailscale to edit the files remotely using TRAMP
, but that is usually pretty slow since my home network is very unreliable. Much easier to just sync “asynchronously” when the network feels like it.
exwm
has other issues, namely around multi-monitor setups. They make sense and are probably sacrifices I would have made had I created exwm
, but I don’t really like working with frames instead of windows. It becomes another layer of friction, even if I’m still working within Emacs.
To try and replicate this behaviour in eww
you have to run (eww-reload t)
, by default bound to C-u g
, to refresh the buffer and reformat it. You can probably run it in a hook whenever you resize windows, but I don’t care to do that.