by Jacques B
Converts Zotero drag-and-drop annotation links into Pandoc-style citations that still link through to the specific PDF annotation.
Zotero Annotation Citations
An Obsidian plugin that converts an annotation pasted from Zotero to a Pandoc citation while maintaining the link to the annotation in Zotero. Zotero links can be bulk removed when the document is ready to be shared, leaving only the Pandoc citations.
You get the deep link functionality of Zotero annotations so you can refer back to sources while researching/writing, but with Pandoc formatted citations for when the document is ready to publish.
Before (what Zotero's drag-and-drop gives you):
([Smith, 2020, p. 5](zotero://select/library/items/ABCD1234)) ([pdf](zotero://open-pdf/library/items/ABCD1234?page=12&annotation=WXYZ5678))
Rendered in Obsidian:
(Smith, 2020, p. 5) (pdf)
After (what this plugin turns it into):
[@smith2020, p. 5](zotero://open-pdf/library/items/ABCD1234?page=12&annotation=WXYZ5678)
Rendered in Obsidian:
@smith2020, p. 5
The result is the Pandoc citation with the BetterBibTex citation key, linked
straight to the highlighted annotation in Zotero. @smith2020 is a real Pandoc
citation, so Pandoc renders it normally in exported documents once the
link has been removed (see Usage below).
Rationale
Using Zotero Quick Copy + the Better BibTeX plugin (Settings > "Quick Copy") you can copy + paste Pandoc style citations for library items. Using the excellent jpeacock29/zotero-cite-links Obsidian plugin you can click these Pandoc citations and be linked to the item in Zotero.
However, this only works for library items, not highlights and other annotations. This plugin addresses that gap. It starts from what Zotero actually hands you on drag-and-drop (or pasted) annotation and converts it to Pandoc citation style, without losing the annotation-level link.
How it works
Turning ITEMKEY into @citekey needs a citekey source. Two are supported:
- Better BibTeX (live Zotero) — the plugin talks to Zotero over
Better BibTeX's local JSON-RPC API (
item.citationkey) and gets an exact answer. Requires Zotero to be running with the Better BibTeX plugin installed. This is the default and the recommended mode. - A local
.bibfile — works offline / without Zotero running. The plugin parses the.bibfile itself and matches each citation by author surname + year (the only information Zotero's drag-and-drop text gives you). This is a best-effort match: if two entries share an author surname and year, you'll get a Notice telling you to double-check.
Usage
By default, conversion happens automatically: drag an annotation from Zotero into Obsidian (or paste a copied annotation) and it's rewritten the moment it lands, with no extra step. Anything that isn't a Zotero citation — images, other links, plain text — is left completely untouched; the plugin only intercepts input that actually matches Zotero's citation format.
If you turn "Convert automatically" off in settings, or you have older Zotero links already sitting in a note, these commands are also available from the command palette:
- Convert Zotero annotation links to Pandoc citations (selection) — converts only the current selection (or the whole note if nothing is selected).
- Convert Zotero annotation links to Pandoc citations (whole note) — converts every match in the active file.
- Remove annotation links from Pandoc citations (whole note, for
export) — once a note is ready to export and you no longer need the
click-through-to-annotation links, this strips the
zotero://link back out of every citation, turning[@smith2020, p. 5](zotero://...)into a plain[@smith2020, p. 5]— a normal Pandoc citation with nothing Zotero-specific left in it.
Either way, a Notice reports how many citations were converted (or how many links were removed) and flags any that couldn't be resolved (left untouched so you don't lose data).
Both your personal library and group libraries are handled — groups/<id>
paths are preserved in the resulting link. Multiple annotations dragged in
together (([A, 2020, p.1](...); [B, 2019, p.2](...)) ([pdf](...)) ([pdf](...)))
are all converted in one pass.
Settings
- Citekey source — Better BibTeX vs. local
.bibfile. - Better BibTeX port — defaults to
23119. - .bib file path — absolute path to your exported
.bibfile (e.g./Users/you/Zotero/library.bib) - Link target — link to the PDF annotation (default) or just the Zotero item.
Installing
Install from the Obsidian app > Settings > Community Plugins.
Building from source
npm install
npm run build
main.js is produced by esbuild from main.ts and transform.ts.
transform.ts holds all the parsing/matching logic and has no dependency
on Obsidian, so it can be tested standalone — see test.mjs
(node test.mjs) for a set of regression checks covering multi-author
citations, group libraries, multi-annotation drags, and both citekey
sources.
Troubleshooting
"Could not reach Zotero / Better BibTeX" even though Zotero is running.
- Confirm Better BibTeX is actually installed and enabled (Zotero → Tools → Add-ons), not just Zotero itself.
- Confirm the port matches — Better BibTeX's preferences (Advanced) let you
change it from the default
23119. - Check for something else on your machine intercepting
127.0.0.1:23119(a firewall, another app, a VPN with local-traffic inspection). - If it's still broken, switch to the
.bibfile mode as a workaround.
Known limitations
- Desktop only (it talks to a local port for Better BibTeX and reads files directly).
- The
.bibfile mode matches by author surname + year only, since that's all the information present in Zotero's drag-and-drop text. If your library has two same-year items by authors with the same surname, use the Better BibTeX mode instead for an exact match.
Disclosures
- Network use. In "Better BibTeX (live Zotero)" mode, the plugin sends
local HTTP requests to
http://127.0.0.1:<port>(default23119) — the port Zotero's Better BibTeX add-on listens on — to ask it for the citekey of an item via its JSON-RPC API. No data leaves your machine; this never talks to anything outside127.0.0.1. - Accessing files outside the vault. In "Local .bib file" mode, the
plugin reads the
.bibfile at the absolute path you give it in settings, which is typically outside your vault (e.g. wherever Zotero/ Better BibTeX exports your library to). This is needed so the plugin can look up citekeys without Zotero running. Desktop only, since it relies on Node's filesystem API.
License
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.