Browse and import bibliographic references from CrossRef, DBLP, HAL, arXiv, Dissemin, and doi.org from Emacs
Emacs Lisp
218
163 commits
updated Aug 12, 2025
biblio.el makes it easy to browse and gather bibliographic references and publications from various sources, by keywords or by DOI. References are automatically fetched from well-curated sources, and formatted as BibTeX.

Quick start: M-x biblio-lookup. Each source can also be accessed independently:
M-x crossref-lookup to query CrossRefM-x arxiv-lookup to query arXivM-x dblp-lookup to query DBLPM-x hal-lookup to query HALM-x ieee-lookup to query IEEE XploreM-x doi-insert to insert a BibTeX record by DOIM-x dissemin-lookup to show information about the open access status of a
particular DOIThese commands work together: for example, crossref-lookup displays a
list of results in biblio-selection-mode. In that mode, use:
RET to visit the corresponding web pagec or M-w to copy the BibTeX record of the current entryi or C-y to insert the BibTeX record of the current entryx to run an extended action, such as fetching a Dissemin recordC and I do the same as c and i, but additionally close the search window.
To insert a clean BibTeX entry for this paper in the current buffer, use
M-x crossref-lookup RET fiat deductive delaware RET i
(the last i inserts the BibTeX record of the currently selected entry in your buffer).
To find publications by computer scientist Leslie Lamport, use M-x dblp-lookup RET author:Lamport RET (see more info about DBLP's syntax at
https://dblp.uni-trier.de/search/)
To check whether an article is freely available online, use x in the list of
results. For example M-x crossref-lookup RET emacs stallman RET followed by
x Dissemin RET will help you find open access copies of Stallman's paper on
EMACS (spoiler: it's here).
Add MELPA to your package sources, then
use M-x package-install RET biblio RET. To get better response
times from CrossRef, you
may consider customizing biblio-crossref-user-email-address.
biblio.elThe extensibility mechanism is inspired by the one of company-mode. See the
docstring of biblio-backends. Here is the definition of biblio-dblp-backend,
for example:
;;;###autoload
(defun biblio-dblp-backend (command &optional arg &rest more)
"A DBLP backend for biblio.el.
COMMAND, ARG, MORE: See `biblio-backends'."
(pcase command
(`name "DBLP")
(`prompt "DBLP query: ")
(`url (biblio-dblp--url arg))
(`parse-buffer (biblio-dblp--parse-search-results))
(`forward-bibtex (biblio-dblp--forward-bibtex arg (car more)))
(`register (add-to-list 'biblio-backends #'biblio-dblp-backend))))
;;;###autoload
(add-hook 'biblio-init-hook #'biblio-dblp-backend)
Note how the autoload registers the backend without loading the entire file.
When biblio-lookup is called by the user, it will run all functions in
biblio-init-hook with 'register as their first argument, and the dblp
backend will be added to the list of backends add that point.
The selection mode menu has an extended action key, x. The only extension at
the moment is Dissemin. Extensions are conses (label . function) added to
biblio-selection-mode-actions-alist; function is called with the metadata of
the current entry when the user selects label (a string) from the list of
extensions after pressing x. For example:
(add-to-list 'biblio-selection-mode-actions-alist
'("Dissemin (find open access copies of this article)" .
biblio-dissemin--lookup-record))
Alternatively, end-users can add new actions directly to the selection menu by
adding custom bindings to the biblio-selection-mode-map keymap. For example,
the following snippet defines a custom action that appends a bibtex entry for
the current selection to the end of the file defined by my/reference-bibfile:
(defun my/biblio--selection-insert-at-end-of-bibfile-callback (bibtex entry)
"Add BIBTEX (from ENTRY) to end of a user-specified bibtex file."
(with-current-buffer (find-file-noselect my/reference-bibfile)
(goto-char (point-max))
(insert bibtex))
(message "Inserted bibtex entry for %S."
(biblio--prepare-title (biblio-alist-get 'title entry))))
(defun ans/biblio-selection-insert-end-of-bibfile ()
"Insert BibTeX of current entry at the end of user-specified bibtex file."
(interactive)
(biblio--selection-forward-bibtex #'my/biblio--selection-insert-at-end-of-bibfile-callback))
By default biblio.el performs only minor cleanups on the BibTeX entries that it downloads from the web. To customize the clean-up phase, add functions to biblio-cleanup-bibtex-function (each such function should take one argument, autokey, indicated whether to generate a new BibTeX key; see biblio-format-bibtex).
For example:
;; Disable cleanups entirely
(setq biblio-cleanup-bibtex-function #'ignore)
;; Replace @data with @misc before further processing
(defun ~biblio-data-to-misc (_autokey)
(save-excursion
(when (search-forward "@data{" nil t)
(replace-match "@misc{"))))))
(add-function
:before biblio-cleanup-bibtex-function
#'~biblio-data-to-misc)
;; Add custom field ‘creationdate’ recording the date when the item was added.
(defun ~biblio-record-creation-date (_autokey)
(save-excursion
(bibtex-make-field "creationdate" t t)
(insert (format-time-string "%Y-%m-%d"))))
(add-function
:before biblio-cleanup-bibtex-function
#'~biblio-record-creation-date)
;; Delete ‘publisher’ field
(defun ~biblio-delete-publisher-field (_autokey)
(save-excursion
(when-let (bounds (bibtex-search-forward-field "publisher" t))
(delete-region (bibtex-start-of-field bounds)
(bibtex-end-of-field bounds)))))
(add-function
:before biblio-cleanup-bibtex-function
#'~biblio-delete-publisher-field)
;; Prevent ‘bibtex-mode’ from inserting tabs
(defun ~biblio-with-spaces-not-tabs (oldfun &rest args)
(let ((indent-tabs-mode nil))
(when oldfun
(apply oldfun args))))
(add-function
:around biblio-cleanup-bibtex-function
#'~biblio-with-spaces-not-tabs)
;; Reverse numbers in ‘pages’ range
(defun ~biblio-reverse-page-numbers (_autokey)
(save-excursion
(when-let (bounds (bibtex-search-forward-field "pages" t))
(goto-char (bibtex-start-of-text-in-field bounds))
(when (re-search-forward "\\([0-9]+\\)\\([-–]+\\)\\([0-9]+\\)"
(bibtex-end-of-text-in-field bounds) t)
(replace-match "\\3\\2\\1" t nil)))))
(add-function
:before biblio-cleanup-bibtex-function
#'~biblio-reverse-page-numbers)
Emacs Lisp
99.6%
Browse and import bibliographic references from CrossRef, DBLP, HAL, arXiv, Dissemin, and doi.org from Emacs
Emacs Lisp
218
163 commits
updated Aug 12, 2025
biblio.el makes it easy to browse and gather bibliographic references and publications from various sources, by keywords or by DOI. References are automatically fetched from well-curated sources, and formatted as BibTeX.

Quick start: M-x biblio-lookup. Each source can also be accessed independently:
M-x crossref-lookup to query CrossRefM-x arxiv-lookup to query arXivM-x dblp-lookup to query DBLPM-x hal-lookup to query HALM-x ieee-lookup to query IEEE XploreM-x doi-insert to insert a BibTeX record by DOIM-x dissemin-lookup to show information about the open access status of a
particular DOIThese commands work together: for example, crossref-lookup displays a
list of results in biblio-selection-mode. In that mode, use:
RET to visit the corresponding web pagec or M-w to copy the BibTeX record of the current entryi or C-y to insert the BibTeX record of the current entryx to run an extended action, such as fetching a Dissemin recordC and I do the same as c and i, but additionally close the search window.
To insert a clean BibTeX entry for this paper in the current buffer, use
M-x crossref-lookup RET fiat deductive delaware RET i
(the last i inserts the BibTeX record of the currently selected entry in your buffer).
To find publications by computer scientist Leslie Lamport, use M-x dblp-lookup RET author:Lamport RET (see more info about DBLP's syntax at
https://dblp.uni-trier.de/search/)
To check whether an article is freely available online, use x in the list of
results. For example M-x crossref-lookup RET emacs stallman RET followed by
x Dissemin RET will help you find open access copies of Stallman's paper on
EMACS (spoiler: it's here).
Add MELPA to your package sources, then
use M-x package-install RET biblio RET. To get better response
times from CrossRef, you
may consider customizing biblio-crossref-user-email-address.
biblio.elThe extensibility mechanism is inspired by the one of company-mode. See the
docstring of biblio-backends. Here is the definition of biblio-dblp-backend,
for example:
;;;###autoload
(defun biblio-dblp-backend (command &optional arg &rest more)
"A DBLP backend for biblio.el.
COMMAND, ARG, MORE: See `biblio-backends'."
(pcase command
(`name "DBLP")
(`prompt "DBLP query: ")
(`url (biblio-dblp--url arg))
(`parse-buffer (biblio-dblp--parse-search-results))
(`forward-bibtex (biblio-dblp--forward-bibtex arg (car more)))
(`register (add-to-list 'biblio-backends #'biblio-dblp-backend))))
;;;###autoload
(add-hook 'biblio-init-hook #'biblio-dblp-backend)
Note how the autoload registers the backend without loading the entire file.
When biblio-lookup is called by the user, it will run all functions in
biblio-init-hook with 'register as their first argument, and the dblp
backend will be added to the list of backends add that point.
The selection mode menu has an extended action key, x. The only extension at
the moment is Dissemin. Extensions are conses (label . function) added to
biblio-selection-mode-actions-alist; function is called with the metadata of
the current entry when the user selects label (a string) from the list of
extensions after pressing x. For example:
(add-to-list 'biblio-selection-mode-actions-alist
'("Dissemin (find open access copies of this article)" .
biblio-dissemin--lookup-record))
Alternatively, end-users can add new actions directly to the selection menu by
adding custom bindings to the biblio-selection-mode-map keymap. For example,
the following snippet defines a custom action that appends a bibtex entry for
the current selection to the end of the file defined by my/reference-bibfile:
(defun my/biblio--selection-insert-at-end-of-bibfile-callback (bibtex entry)
"Add BIBTEX (from ENTRY) to end of a user-specified bibtex file."
(with-current-buffer (find-file-noselect my/reference-bibfile)
(goto-char (point-max))
(insert bibtex))
(message "Inserted bibtex entry for %S."
(biblio--prepare-title (biblio-alist-get 'title entry))))
(defun ans/biblio-selection-insert-end-of-bibfile ()
"Insert BibTeX of current entry at the end of user-specified bibtex file."
(interactive)
(biblio--selection-forward-bibtex #'my/biblio--selection-insert-at-end-of-bibfile-callback))
By default biblio.el performs only minor cleanups on the BibTeX entries that it downloads from the web. To customize the clean-up phase, add functions to biblio-cleanup-bibtex-function (each such function should take one argument, autokey, indicated whether to generate a new BibTeX key; see biblio-format-bibtex).
For example:
;; Disable cleanups entirely
(setq biblio-cleanup-bibtex-function #'ignore)
;; Replace @data with @misc before further processing
(defun ~biblio-data-to-misc (_autokey)
(save-excursion
(when (search-forward "@data{" nil t)
(replace-match "@misc{"))))))
(add-function
:before biblio-cleanup-bibtex-function
#'~biblio-data-to-misc)
;; Add custom field ‘creationdate’ recording the date when the item was added.
(defun ~biblio-record-creation-date (_autokey)
(save-excursion
(bibtex-make-field "creationdate" t t)
(insert (format-time-string "%Y-%m-%d"))))
(add-function
:before biblio-cleanup-bibtex-function
#'~biblio-record-creation-date)
;; Delete ‘publisher’ field
(defun ~biblio-delete-publisher-field (_autokey)
(save-excursion
(when-let (bounds (bibtex-search-forward-field "publisher" t))
(delete-region (bibtex-start-of-field bounds)
(bibtex-end-of-field bounds)))))
(add-function
:before biblio-cleanup-bibtex-function
#'~biblio-delete-publisher-field)
;; Prevent ‘bibtex-mode’ from inserting tabs
(defun ~biblio-with-spaces-not-tabs (oldfun &rest args)
(let ((indent-tabs-mode nil))
(when oldfun
(apply oldfun args))))
(add-function
:around biblio-cleanup-bibtex-function
#'~biblio-with-spaces-not-tabs)
;; Reverse numbers in ‘pages’ range
(defun ~biblio-reverse-page-numbers (_autokey)
(save-excursion
(when-let (bounds (bibtex-search-forward-field "pages" t))
(goto-char (bibtex-start-of-text-in-field bounds))
(when (re-search-forward "\\([0-9]+\\)\\([-–]+\\)\\([0-9]+\\)"
(bibtex-end-of-text-in-field bounds) t)
(replace-match "\\3\\2\\1" t nil)))))
(add-function
:before biblio-cleanup-bibtex-function
#'~biblio-reverse-page-numbers)
Emacs Lisp
99.6%