This vignette follows one manuscript from the first citation to a rendered document. The chunks that need your Zotero account are shown but not run here; the parts that work offline are run.
Before starting you need a Zotero API key, your user ID in
~/.Renviron, and citekeys on your items.
vignette("setup") walks through this. Check that citezot
can see your credentials (the key is never printed):
In manuscript.qmd, cite as usual and point Quarto at the
file citezot will write:
---
title: "On the Origin of Species"
bibliography: references.bib
---
The origin of species is explained by @Darwin1859; see also @Weiß2015.Citezot finds the citations in the text. Code chunks are ignored, as
are Quarto cross-references such as @fig-map:
qmd <- tempfile(fileext = ".qmd")
writeLines(c(
"---",
"bibliography: references.bib",
"---",
"The origin of species is explained by @Darwin1859; see also @Weiß2015 and @fig-map.",
"",
"```{r}",
"x@slot # not a citation",
"```"
), qmd)
cz_qmd_keys(qmd)#> [1] "Darwin1859" "Weiß2015"
Now write the bibliography:
and render the document with Quarto as normal
(quarto render manuscript.qmd, to HTML, PDF or Typst). Only
the cited items are written, in key order, as BibLaTeX straight from
Zotero’s exporter. For CSL-YAML give a .yaml name:
cz_update_bib("manuscript.qmd", out = "references.yaml").
Suppose the text cites @Kent2002 but the item has no
such citekey in Zotero. The update stops and does not touch your
existing file:
cz_update_bib("manuscript.qmd")
#> Error in `cz_update_bib()`:
#> ! Cited in the documents but not found in Zotero: "Kent2002".
#> ✖ 'references.bib' was NOT touched, because an incomplete bibliography would
#> break the render.
#> ℹ Pin the citekey in Zotero (see `cz_pin_key()`), check the spelling, or use
#> `allow_incomplete = TRUE` to write what was found.Three things can be wrong, and citezot helps with each.
A typo, or the item is there under another key. Search for it:
The item is in Zotero but has no key yet. Pin one. Like every write, it is a dry run until you say so:
The item is not in your library. Add it from its DOI:
cz_add("10.1101/gr.229202", key = "Kent2002") # preview
cz_add("10.1101/gr.229202", key = "Kent2002", dry_run = FALSE) # createThe preview shows the title, authors, date and key it would create,
and cz_add() first checks that the DOI and the key are not
already in your library. (Only DOIs registered with Crossref are
supported so far.)
Run cz_update_bib() again and the document is
complete.
A date is wrong. Preview the change, then apply it:
cz_update_item("Regnier2024", list(date = "in press"))
#> ℹ Dry run: nothing written. Use `dry_run = FALSE` to apply to item ABCD2345 (...).
#> • date: "2026" -> "in press"
cz_update_item("Regnier2024", list(date = "in press"), dry_run = FALSE)Only fields that change are sent, together with the item’s version.
If someone (or Zotero desktop) edited the item after citezot read it,
Zotero answers HTTP 412 and nothing is overwritten; run the command
again after looking at the item with
cz_get_item("Regnier2024"). Creators, tags and collections
are replaced as a whole, so to add one tag pass the full list of tags.
Identity fields (key, version,
itemType, dates added/modified) and the citekey cannot be
changed here; use cz_pin_key() for the key.
If you use Better BibTeX, your keys follow a pattern such as
auth.lower + year + shorttitle(1).lower. citezot can
generate keys for new items with the same pattern:
item <- list(
itemType = "journalArticle",
title = "On the origin of species by means of natural selection",
date = "1859",
creators = list(list(creatorType = "author", firstName = "Charles", lastName = "Darwin"))
)
cz_suggest_key(item, "auth.lower + year + shorttitle(1).lower")
#> [1] "darwin1859origin"
# a taken key gets a letter
cz_suggest_key(item, "auth.lower + year + shorttitle(1).lower",
existing = "darwin1859origin")
#> [1] "darwin1859origina"
# Better BibTeX's own default pattern
cz_suggest_key(item, "auth.lower + shorttitle(3,3) + year")
#> [1] "darwinOriginSpeciesMeans1859"cz_add(..., key = "auto") uses the pattern from
cz_key_format(): the citezot.key_format option
if you set it, otherwise the one Better BibTeX saved in your Zotero
profile, otherwise Better BibTeX’s default. Only a subset of the formula
language is supported (auth, year,
shorttitle, title, a few filters,
+); anything else is an error rather than a different key.
Better BibTeX itself is not needed: any key you pin with
cz_pin_key() or give to cz_add() works.
Words in titles follow Better BibTeX’s rules: HTML tags are dropped,
titles are cut at the first colon or sentence end, short function words
such as “a” and “the” are skipped, and hyphens and other punctuation are
removed inside words (early-diverging becomes
earlydiverging).
A first download of a big library takes tens of seconds. Turn on the cache and later runs only fetch what changed:
options(citezot.cache = TRUE) # put this in your .Rprofile
system.time(cz_update_bib("manuscript.qmd"))
#> user system elapsed
#> 0.121 0.019 0.342The cache lives in tools::R_user_dir("citezot", "cache")
and holds bibliographic metadata only.
cz_fetch_items(refresh = TRUE) forces a full download, and
cz_clear_cache() deletes it.
Update the bibliography every time the project renders by adding a
pre-render step to _quarto.yml:
In a targets pipeline, return the path and let targets track the file:
tar_target(
references,
cz_update_bib("manuscript.qmd", quiet = TRUE),
format = "file",
cue = tar_cue(mode = "always")
)Because cz_update_bib() leaves the file alone when
nothing changed, the render is only repeated when your references really
changed.
Sys.getenv("ZOTERO_API_KEY") != "" and restart R after
editing ~/.Renviron.cz_get_item() and retry on
purpose.cz_find() to see what the item’s key is, and
cz_pin_key() to set it.??) cannot be cited from a document. Fix it in Zotero or
with cz_pin_key(..., overwrite = TRUE).