zot provides an R interface to the Zotero Web API,
read-only queries over a local Zotero database, batch-plan execution,
bibliographic comparison, and selected external integrations.
The public documentation is available at https://kanameishi.github.io/zot/.
| Topic | Article |
|---|---|
| Configuration and data sources | Get started with zot |
| Curation plans | Curation plans |
| Batch execution | Batch execution with zot |
| External integrations | External integrations |
| Command line | The zot command line |
| Installation and package maintenance | Source installation |
Install the released package from CRAN:
install.packages("zot")The library and the zot command-line interface are
installed together from the repository root with the product installer,
documented in install/USAGE.md. Package maintenance scripts
are part of the package under inst/ and run from
lib/, as the source
installation article describes. The RStudio project for package
development is inside lib/.
zotConfig() accepts a Zotero user identifier and API key
explicitly:
library(zot)
Config <- zotConfig(
userID = "42",
key = "example-key"
)With no arguments, it reads ZOTERO_LIBRARY_ID and
ZOTERO_API_KEY from the process environment:
Config <- zotConfig()A non-interactive caller reads no shell profile, so an
Rscript job started by cron,
make, or an external tool takes both variables from
~/.Renviron, the file R reads at startup in every
session.
Printing the object omits the API key. The default
library = "user" selects the configured personal library;
numeric group identifiers are passed through the library
argument of the relevant functions.
This explicit configuration interface is suitable for interactive sessions, scripts, automated jobs, and agent-driven workflows. The package does not select an authorization policy for its callers.
The package exposes two read paths:
| Source | Entry points | Characteristics |
|---|---|---|
| Local Zotero database | zotLocalItems(), zotLocalQuery() |
Read-only SQLite queries; may lag remote state |
| Zotero Web API | zotGet(), zotGetAll(),
ztCensus() |
Current remote records and response metadata |
For example, a local query does not modify the Zotero database:
Items <- zotLocalItems(library = "user")
Items[, .(key, itemType, title)]A paginated API request uses the configured user library:
Path <- paste0(zotLibraryPath(Config), "/items/top")
Items <- zotGetAll(Config, path = Path, query = list(format = "json"))Plan builders return data.table objects without
executing the represented changes. This example normalizes copy suffixes
and file extensions in titles:
library(data.table)
Items <- data.table(
itemKey = c("A", "B"),
library = "user",
title = c("Reviewed book (1).pdf", "Existing title")
)
Plan <- ztRetitle(Items, transform = ztCleanTitle)
Preview <- zotPreview(Plan, describe = "Normalize reviewed titles")
PreviewOther functions build collection-membership plans, compare possible duplicate records, map Crossref metadata, and divide cross-library moves into create and Trash phases.
zotPreview() validates a plan, copies it, and records
its digest. zotApprove() creates a record containing that
digest and optional notes. zotExecute() requires matching
preview and approval digests, applies rows, and writes a resumable
ledger. zotVerify() samples completed patch rows and
compares their requested fields with current API data.
Approval <- zotApprove(Preview, notes = "Reviewed batch")
Ledger <- zotExecute(
Config,
preview = Preview,
approval = Approval,
ledgerPath = "zot-ledger.json"
)
zotVerify(Config, preview = Preview, ledger = Ledger)An approval object is an application record, not an authentication
mechanism. Callers should treat a preview as immutable after approval.
The executor checks that the approval and preview digests match, then
recalculates the digest from preview$plan; an altered plan
is rejected before any request.
New ledgers use schema 2 and library:key identities for
existing items; create rows retain create-<row>. A
created key is saved before its read-back. If that read fails, resuming
confirms the saved key without another POST. An unknown POST outcome
remains an attempt requiring reconciliation. POST server
errors are not retried automatically; explicit rate limiting retains the
transport’s bounded retry behavior. Legacy key-only ledgers retain their
format when every identity maps to one plan row. Ambiguous legacy keys
and legacy failed creates with a potentially lost key require
reconciliation; the executor does not migrate those files. Verification
counts absent plan rows as pending and does not report them as complete.
Its default read-back still samples completed patches; use
full = TRUE to check all completed rows.
The package also exports functions with immediate external effects,
including zotPost(), zotPatch(),
zotTrash(), ztCollectionTree(), and
ztAttach(). Callers are responsible for deciding when those
operations are appropriate.
ztCrossref() maps DOI metadata into a Zotero item
payload. ztAttach() implements Zotero’s file-upload
protocol and verifies the stored MD5 after an upload.
See vignette("zot", package = "zot") for an introductory
workflow, vignette("guarded-workflow", package = "zot") for
an offline batch example, and
vignette("external-integrations", package = "zot") for
dependency and effect details.