
retraction scans your manuscripts, bibliographies, and
reference lists for citations to retracted papers, so you do not cite
discredited work. It reads a wide range of document and bibliography
formats, extracts and normalizes identifiers, checks them against
retraction data, and returns a tidy, confidence-scored report.
The default data source is the Retraction Watch database, served through the XeraRetractionTracker API. Crossref and OpenAlex are available as additional, reconcilable sources.
# Development version from GitHub:
# install.packages("pak")
pak::pak("choxos/retraction")library(retraction)
# Check a manuscript, bibliography, or reference file.
result <- check_file("manuscript.Rmd")
result
# Check a vector of DOIs or PMIDs directly.
check_dois(c("10.1016/S0140-6736(97)11096-0", "10.1038/s41586-020-2649-2"))
# Check a data frame of references (columns are auto-detected).
check_refs(retraction_example)A result is a tidy tibble, one row per reference, with the retraction
status, an is_retracted flag, a match
confidence, the retraction_date,
days_since_retraction, the reason, and which
sources confirmed it. Printing it gives a compact summary
and lists the flagged citations.
Two levels of parsing:
.bib), CSL-JSON (.json), RIS
(.ris), EndNote XML, and JATS XML..docx), PDF (.pdf, needs the optional
pdftools package), and text documents (.Rmd,
.qmd, .tex, .md,
.txt, .html). In these formats, references
that do not carry a DOI in the text are not detected.Given a PMID, PMCID, DOI, title, or a whole reference,
check_pmc() resolves it to a PubMed Central article, tells
you whether the open-access full text is available, and if so checks
that article’s reference list for retractions.
res <- check_pmc(c("PMC5334499", "10.1371/journal.pone.0000217", "29939664"))
pmc_articles(res) # open-access status, reference count, and retracted count per input
retracted(res) # the retracted references foundEvery check_*() function takes a sources
argument. The default is "xera" (Retraction Watch). Also
available: "crossref", "openalex",
"europepmc", "ncbi" (PubMed),
"datacite", and "preprint" (arXiv/bioRxiv
withdrawals). You can query more than one, or "all", and
have the results reconciled:
check_dois("10.1016/S0140-6736(97)11096-0",
sources = c("xera", "europepmc", "ncbi"))
list_backends() # available sources
check_dois("10.1126/science.aac4716", sources = "all")
options(retraction.sources = c("xera", "openalex")) # set a session defaultWhen several sources are queried, the highest-priority match sets the
verdict, every confirming source is recorded (with dissenters in
disagreeing), and a disagreement flag is
raised when sources do not agree.
Two caveats worth knowing:
is_retracted flag is itself derived from
Retraction Watch, so Xera and OpenAlex are not fully independent; a
disagreement between them usually reflects OpenAlex lagging rather than
a genuine conflict.xera) source.Offline mode is fully local: it does not contact the network. (An
optional staleness notice is available with
options(retraction.check_freshness = TRUE), which makes one
small request during offline checks.)
For bulk checking, privacy (checking an unpublished manuscript sends only DOIs), or working without a connection, build a local snapshot once and match against it. Updates are incremental, adding new retractions rather than re-downloading everything.
retraction_sync() # download once
check_file("manuscript.Rmd", offline = TRUE)
retraction_sync() # later: incremental updateIf your snapshot falls behind the live database, the package tells you when you run an offline check.
result <- check_file("manuscript.docx")
render_report(result, "report.html") # self-contained HTML, no extra software
render_report(result, "report.md", format = "md")Within a source, matching runs a cascade: exact DOI, then PMID (matched directly against the Retraction Watch corpus, both online and offline, falling back to OpenAlex only to obtain a DOI for the other sources), then fuzzy title matching for references that carry no identifier. When several sources are selected they are all queried and their verdicts reconciled. Exact identifier matches are asserted with high confidence; fuzzy matches are reported as “possible” so you can verify them, and are never asserted as retracted. Fuzzy and PMID matching are most reliable in offline mode, where the full corpus is available locally.
The confidence column is a match-quality heuristic
(exact identifier vs. fuzzy title, adjusted for year and author
agreement), not a calibrated probability.
A citation of a retraction notice (rather than of the retracted work) is recognized and not flagged. A work that was retracted and later reinstated is reported as reinstated, not flagged.
Retraction data comes from the Retraction Watch database, made
openly available through Crossref
and served by XeraRetractionTracker.
The optional Crossref and OpenAlex backends use their public APIs;
OpenAlex’s is_retracted flag is itself derived from
Retraction Watch. See the LICENSE.note file shipped with
the package (and in the source repository) for the full data-provenance
note covering every source.
Parts of retraction were developed with the assistance
of AI coding tools (Anthropic’s Claude, via Claude Code), including code
drafting, documentation, and test scaffolding. All AI-assisted output
was reviewed, tested, and verified by the author, who is solely
responsible for the package and its correctness.
GPL-3. See the LICENSE file.