I have added in my init something like:

(defun today-CA ()
  (eww "https://www.google.com"))

This opens eww through the today-CA function. I want to open it in readabe form, i.e. as if eww-readable had been invoked in the eww buffer. How to do that? This doesn't work:

(defun today-CA ()
  (eww "https://www.google.com")

3 Answers 3


This doesn't work

The reason calling eww-readable right after eww does not work is because eww is asynchronous; when eww-readable is called the eww buffer is not yet rendered, so there are no "unreadable" parts to omit.

How to do that?

There may be a more elegant way, but if you have lexical binding (see the last section) enabled in your init file, you can write something like the following:

(defun today-ca ()
  "Open Google homepage in `eww' with `eww-readable' enabled."
  (letrec ((nonce (lambda ()
                      (remove-hook 'eww-after-render-hook nonce)))))
    (add-hook 'eww-after-render-hook nonce))
  (eww "https://google.com"))

The basic idea is adding the function eww-readable to eww-after-render-hook, so that it is run in the finalised buffer. The only issue lies in cleaning up the hook so that eww-readable does not apply all the time.

We can't call remove-hook right after eww because eww-after-render-hook will not have been run by that point. So the function we add to eww-after-render-hook must remove itself. With lexical-binding we can just create a closure as per my previous example. Alternatively, you could write an additional global helper function:

(defun my-eww-readable-nonce ()
  "Once-off call to `eww-readable' after EWW is done rendering."
    (remove-hook 'eww-after-render-hook #'my-eww-readable-nonce)))

(defun today-ca ()
  "Open Google homepage in `eww' with `eww-readable' enabled."
  (add-hook 'eww-after-render-hook #'my-eww-readable-nonce)
  (eww "https://google.com"))

You could remove the call to unwind-protect, but it ensures the hook is cleaned up even if something in eww-readable fails.


You can also load the content manually with url-retrieve and render it in eww yourself, and then run eww-readable, like this

(defun t/eww-readable-after-render (status url buffer)
  (eww-render status url nil buffer)
  (switch-to-buffer buffer)

(defun t/eww-readable (url)
  (interactive "sEnter URL: ")
  (let ((buffer (get-buffer-create "*eww*")))
    (with-current-buffer buffer
      (autoload 'eww-setup-buffer "eww")
      (url-retrieve url 't/eww-readable-after-render (list url buffer)))))

Using Basil's answer, here is a solution for using eww to browse dash API docs - effectively making dash API docs open in eww buffers that are then collapsed to "readable" form. eww-readable-url can also prompt for a URL to open in eww-readable form if you pass nil and can be called interactively from anywhere to open a eww-readable browser.

       (browse-url-browser-function 'eww-browse-url) 
       (dash-docs-browser-func 'eww-readable-url)
       (use-package helm-eww)
       (defun make-eww-readable()
         ;; make current eww buffer eww-readable and then remove the hook that called this so normal buffers are not eww-readable.
           (remove-hook 'eww-after-render-hook #'make-eww-readable)))

       (defun eww-readable-url (url)
         ;; when the eww buffer has rendered call a hook function that implements eww-readable and then removes that hook.
         ;; primarily for 'dash-docs-browser-func
         (interactive "sURL:")
         (add-hook 'eww-after-render-hook #'make-eww-readable)
         (eww url))
       ("C-c o" . 'browse-url)
       ("C-c O" . 'eww-readable-url)
       (:map eww-mode-map
             ("O" . www-open-current-page-external) 
             ("o" . www-open-link-external)))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.