Zotero
Manage Zotero reference libraries via the Web API. Search, list, add items by DOI/ISBN/PMID (with duplicate detection), delete/trash items, update metadata and tags, export in BibTeX/RIS/CSL-JSON, bat
Manage Zotero reference libraries via the Web API. Search, list, add items by DOI/ISBN/PMID (with duplicate detection), delete/trash items, update metadata and tags, export in BibTeX/RIS/CSL-JSON, bat
Real data. Real impact.
Emerging
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
Interact with Zotero personal or group libraries via the REST API v3.
Requires two environment variables:
ZOTERO_API_KEY — Create at https://www.zotero.org/settings/keys/new ZOTERO_USER_ID — Found on the same page (numeric, not username)
For group libraries, set
ZOTERO_GROUP_ID instead of ZOTERO_USER_ID.
Optional env var for CrossRef/Unpaywall polite pool (improves DOI lookup success rate):
CROSSREF_EMAIL — Your email (optional; uses fallback if unset)
If credentials are missing, tell the user what's needed and link them to the key creation page.
All operations use
scripts/zotero.py (Python 3, zero external dependencies).
python3 scripts/zotero.py <command> [options]
| Command | Description | Example |
|---|---|---|
| List top-level items | |
| Search by query | |
| Full item details + attachments | |
| List all collections | |
| List all tags | |
| List attachments/notes for item | |
| Add item by DOI (dedup enabled) | |
| Add item by ISBN (dedup enabled) | |
| Add item by PubMed ID | |
| Move items to trash (recoverable by default) | |
| Modify item metadata/tags | |
| Export as BibTeX/RIS/CSL-JSON | |
| Add multiple items from file | |
| Report which items have/lack PDFs | |
| Match citations vs library | |
| Find & add missing DOIs via CrossRef | |
| Fetch open-access PDFs for items | |
--json — JSON output instead of human-readable (works with items, search, get)--limit N — Max items to return (default 25)--sort FIELD — Sort by dateModified, title, creator, date--direction asc|desc — Sort direction--collection KEY — Filter by or add to collection--type TYPE — Filter by item type (journalArticle, book, conferencePaper, etc.)--tags "tag1,tag2" — Add tags when creating items--force — Skip duplicate detection on add commandspython3 zotero.py add-doi "10.1093/jamia/ocaa037" --tags "review" # Warns if already in library. Use --force to override.
Duplicate detection: translates DOI to metadata, searches library by first author, compares DOI fields.
# One identifier per line, # for comments python3 zotero.py batch-add dois.txt --type doi --tags "imported"
Skips duplicates. Reports summary: added/skipped/failed.
python3 zotero.py export --format bibtex --output refs.bib python3 zotero.py export --format csljson --collection COLLKEY
python3 zotero.py update ITEMKEY --add-tags "important" --remove-tags "unread" python3 zotero.py update ITEMKEY --title "Corrected Title" --date "2024" python3 zotero.py update ITEMKEY --doi "10.1234/example" python3 zotero.py update ITEMKEY --url "https://example.com/paper" python3 zotero.py update ITEMKEY --add-collection COLLKEY
python3 zotero.py delete KEY1 KEY2 --yes # Trash (recoverable, default) python3 zotero.py delete KEY1 --permanent --yes # Permanent delete
python3 zotero.py crossref my-paper.txt
Extracts
Author (Year) patterns from text and matches against library.
# Dry run (default) — show matches without writing anything python3 zotero.py find-dois --limit 20Actually write DOIs to Zotero
python3 zotero.py find-dois --apply
Filter by collection
python3 zotero.py find-dois --collection COLLKEY --apply
Scans journalArticle and conferencePaper items missing DOIs, queries CrossRef, and matches by title similarity (>85%), exact year, and first author last name. Dry run by default — use
--apply to write. Only patches the DOI field; never touches other metadata. 1s delay between
CrossRef requests (polite pool with mailto).
# Dry run — show which PDFs are available and from where python3 zotero.py fetch-pdfs --dry-run --limit 10Fetch and attach as linked URLs (no storage quota used)
python3 zotero.py fetch-pdfs --limit 20
Also save PDFs locally
python3 zotero.py fetch-pdfs --download-dir ./pdfs
Upload to Zotero storage instead of linked URL
python3 zotero.py fetch-pdfs --upload --limit 10
Only try specific sources
python3 zotero.py fetch-pdfs --sources unpaywall,semanticscholar
Tries three legal OA sources in order: Unpaywall → Semantic Scholar → DOI content negotiation. By default creates linked URL attachments (no Zotero storage quota needed). Use
--upload for
full S3 upload to Zotero storage. Use --download-dir to also save PDFs locally.
Sources:
unpaywall, semanticscholar, doi (default: all three)
Rate limits: 1s between Unpaywall/Semantic Scholar requests, 2s between DOI requests.
python3 zotero.py --json items --limit 100 | jq '.items[].DOI' python3 zotero.py --json get ITEMKEY | jq '.title'
10.xxxx/... format. Item keys are 8-char alphanumeric (e.g., VNPN6FHT). ISBNs must be valid checksums.check-pdfs fetches all items; for large libraries (500+), this may be slowfetch-pdfs also processes all items — use --collection to scope for large librariesNo automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.