How to use quartobot in a Quarto website

Wire the pre-render hook into a Quarto website project, share one bibliography across pages, handle per-page citation lists.

quartobot’s pre-render hook works on every Quarto project type, but the documentation so far has been manuscript-shaped. Websites change three things worth covering on their own page: one references.json shared across all pages, format.html.bibliography: resolves relative to each page, and the _freeze/ cache interacts with cite-key changes in unobvious ways. The rest is the same.

Minimal wiring

Quarto’s own scaffolder writes the website layout:

quarto create project website my-site
cd my-site

Layer the citation pipeline on top:

quartobot init

Same UX as the manuscript path. Because quarto create project already wrote a _quarto.yml, init will not touch it; it prints a YAML snippet to paste in yourself. Merge the snippet under the existing project: block. The resulting _quarto.yml looks like:

project:
  type: website
  pre-render: quartobot resolve --from-scan . --id-mode citation-key

website:
  title: "My site"
  navbar:
    - href: index.qmd
      text: Home
    - href: about.qmd
      text: About

bibliography:
  - references.bib
  - references.resolved.bib

init also seeds an empty references.bib for hand-curated entries (anything without a persistent identifier — a personal communication, a webpage with no DOI) and adds _freeze/, .quarto/, *_files/, and references.json to .gitignore.

That’s the wiring. Every quarto render and quarto preview now runs quartobot resolve first; pandoc-citeproc reads the resulting references.json alongside references.bib.

Per-page citation lists

A website is multiple pages. Some cite, some don’t. The pre-render hook does not care: quartobot scan walks the whole project, quartobot resolve resolves every cite key it finds across every page into one shared references.json at the project root. The bibliography is one file, not one per page.

Each page’s rendered HTML carries only the references actually cited on that page. That’s pandoc-citeproc’s default — it filters the bibliography down to the keys cited in the document. A page that cites nothing renders with no reference list at all. A page that cites three keys renders with three entries, even though references.json holds dozens.

If you need an entry to appear in a page’s bibliography list without an inline citation — a “further reading” section, say — pandoc’s nocite: field in the page frontmatter forces it in:

---
title: "About"
nocite: |
  @doi:10.1371/journal.pcbi.1007128
---

That is pandoc behavior, not quartobot’s, and it’s documented in the pandoc manual under “Including uncited items in the bibliography.”

Freeze cache and cite-key changes

Quarto’s _freeze/ directory caches rendered output per page so that quarto render skips pages whose source hasn’t changed. The interaction with the pre-render hook has one gotcha worth knowing.

When you change a cite key inside a .qmd page, _freeze/ invalidates that page (its source hash changed) but does not invalidate references.json. The pre-render hook runs on every render anyway, so the new key gets resolved and the bibliography updates correctly. This works the way you’d want.

The case that bites: you change only _quarto.yml’s bibliography: list — add a second .bib file, say. No .qmd source hash changes, so _freeze/ thinks nothing needs re-rendering, and the new bibliography entries never reach the rendered HTML. Run quarto render --no-freeze once to bust the cache. After that, normal quarto render picks up the new bibliography on every page.

Worked example

A two-page site sharing one bibliography.

my-site/
├── _quarto.yml
├── index.qmd
├── methods.qmd
├── references.bib
└── references.resolved.bib   # generated by quartobot resolve

_quarto.yml:

project:
  type: website
  pre-render: quartobot resolve --from-scan . --id-mode citation-key

website:
  title: "Lab notebook"
  navbar:
    - href: index.qmd
      text: Home
    - href: methods.qmd
      text: Methods

bibliography:
  - references.bib
  - references.resolved.bib

index.qmd:

---
title: "Home"
---

The manubot pattern [@doi:10.1371/journal.pcbi.1007128] runs scholarly
writing as software.

methods.qmd:

---
title: "Methods"
---

GTEx Consortium pilot data [@pmid:23715323] is the worked example.

Render:

quarto render

The pre-render hook scans both pages, resolves both keys (one via Crossref, one via PubMed), and writes references.resolved.bib with both entries. Pandoc-citeproc reads references.bib + references.json per page and emits one reference list per page: index.html carries the manubot citation, methods.html carries the GTEx citation, neither carries the other’s. A third page citing both keys would carry both entries; a fourth citing neither would carry no reference list at all. That’s pandoc-citeproc’s default, not quartobot’s.

See also