Is there a way to have org-mode automatically set the description from the html page's when inserting a link into org-mode?


2 Answers 2


There's a package called org-cliplink precisely for this.

Alternatively, if you'd like to calculate your own title based on DOM queries instead of using org-cliplink's simple logic that just looks at the <title>, here's a simplified version of how I do this in my config:

(use-package dash :ensure t)
(use-package s :ensure t)

(defun my-org-link-description (url &rest _)
  "Return link description for URL in the format I use in my notes."
  (require 'cl-lib)
  (require 'dash)
  (require 's)
  (require 'dom)
  (let* ((url ; Use old.reddit.com (the new version is a huge JavaScript mess).
           "\\1old.\\2" url))
         (html-buffer (url-retrieve-synchronously url))
         (dom (with-current-buffer html-buffer
                (libxml-parse-html-region (point-min) (point-max) url t)))
         (title (s-trim (dom-text (car (dom-by-tag dom 'title)))))
         (parsed-url (url-generic-parse-url url))
         (host (url-host parsed-url))
         (domain-levels ; E.g. '("com" "ycombinator.com" "news.ycombinator.com")
          (nreverse (-reduce-r-from
                     (lambda (new-part accum)
                       (cons (if accum
                                 (concat new-part "." (car accum))
                     nil (s-split "\\." host))))
         (path (url-filename parsed-url))
         match-1 match-2) ; Temporary variables for later use.

     ;; Reddit comment thread.
     ((and (string-equal "reddit.com" (nth 1 domain-levels))
           (setq match-1 (s-match "^/r/\\([^/]+\\)/comments/" path))
           (setq match-2 (s-match "^\\([^ ]+\\) comments on \\(.+\\)$" title)))
      (let ((subreddit (nth 1 match-1))
            (commenter (nth 1 match-2))
            (top-level-title (nth 2 match-2)))
        (concat "Reddit /r/" subreddit ": " commenter " on " top-level-title)))

     ;; Hacker News comment thread.
     ((and (string-equal "news.ycombinator.com" (nth 2 domain-levels))
           (setq match-1 (dom-by-tag (dom-by-class dom "storyon") 'a)))
      (let ((parent-title (dom-text (car match-1)))
            (user (dom-text (car (dom-by-class dom "hnuser")))))
        (concat "Hacker News: " user " on " parent-title)))

     ;; Pages whose title probably contains the website's name.
     ((setq match-1 (s-match "^\\(.*\\) [-–|:•#·»←] \\(.*\\)$" title))
      (cl-destructuring-bind (_ first-part second-part) match-1
        (let* ((first-longer-p (>= (length first-part) (length second-part)))
               (longer (if first-longer-p first-part second-part))
               (shorter (if first-longer-p second-part first-part)))
          (concat shorter ": " longer))))

     ;; Others.
     (t title))))

(defun my-org-insert-link ()
  "Insert link in the format I use in my notes."
  (let ((org-make-link-description-function #'my-org-link-description))
    (call-interactively #'org-insert-link)))

(with-eval-after-load 'org
  (bind-key "C-c M-l" #'my-org-insert-link org-mode-map))

In addition to org-cliplink I find the asamuzaK/url2clipboard browser extension really useful and actually use it more than org-cliplink as I can bind the org-mode copying to a key sequence (I use Alt-o) which places an org-formatted link in the clipboard then in Emacs its your usual C-y to paste into the buffer.

The browser extension is available for Firefox and Chrome based browsers.

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.