Crossref logo

Research · Live on Apify

DOI Metadata and Bibliography Enrichment

Paste a list of DOIs and get one clean citation record each. The tool asks the right agency for each DOI. Bad or unknown DOIs get a clear status.

About $1.80 for 1,000 DOI records$0.0018 per DOI record + $0.001 per run. Apify bills you, not us.Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed.

Run it on Apify Opens apify.com, the website where our tools run. Sign up free with Google or email, no card needed.

Apify links on this page are affiliate links. We may earn a commission. You pay the same price. Affiliate disclosure

What you get, for example

doi10.1038/nature12373
doiUrlhttps://doi.org/10.1038/nature12373
agencyCrossref

How to use it: 3 steps

  1. Make a free Apify accountApify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
  2. Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example: 10.1038/nature12373 in DOIs. Each start is one run.
  3. Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.

This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.

What it does

Paste a list of DOIs and get one clean citation record per DOI. This bulk DOI metadata lookup checks each DOI at doi.org, reads the metadata from the official Crossref, DataCite or JaLC API, and returns title, authors, journal or book, exact dates, volume, pages, ISSN/ISBN, license and citation counts.

  • Cleans your input. It accepts 10.…, doi:10.…, https://doi.org/10.… and dx.doi.org links, in any letter case.
  • Asks doi.org which agency registered each DOI.
  • Reads the record from that agency: Crossref (most journals and books), DataCite (datasets, software, repositories) or JaLC (Japan).
  • Writes one Dataset row for each input value, in your input order, with a clear status.

Good for

  • Turn a list of DOIs into a table of titles, authors, journals, years and pages.
  • Check a reference list: find DOIs that are not registered or have a typo.
  • Add ISSN, ISBN, publisher, license and citation counts to a list of papers.
  • Mix journal articles and research datasets in one run (Crossref and DataCite).

Not a good fit

  • No search by title or author. You need the DOI.
  • No PDFs, full text or abstracts. The Actor reads only bibliographic metadata.
  • No Open Access links (for example from Unpaywall).
  • DOIs from other agencies (for example mEDRA) are only identified. The row has status: unsupported_agency and the agency name, but no title or authors.
  • No BibTeX or RIS file. You get structured fields that you can export as JSON, CSV or Excel.
  • Up to 500 DOIs per run.

Who uses it

Researchers and students

Turn a DOI list into a reference table.

Librarians

Find typos and unregistered DOIs in a list.

Research offices

Add journals, ISSN and licenses to paper lists.

Price

Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.

What you pay forPriceWhen
Start fee$0.001Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more.
DOI metadata record$0.0018 (from $0.0015 on paid Apify plans)One unique DOI with a metadata row saved to the Dataset: a complete row, or a partial row that has metadata but no title (NO_TITLE). Repeated DOIs are free.
DOI check without metadata$0.0005One unique DOI checked without metadata: doi.org reports it as not registered, it belongs to an agency this Actor does not read, or the agency has no record yet (not_found, unsupported_agency or RECORD_NOT_INDEXED row).

Examples

  • One DOI record: about $0.0028.
  • 1,000 DOI records: about $1.80.
  • Every day 100 DOI records, for 30 days: about $5.43 a month.

Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed. That is enough for about 2,700 DOI records.

Prices checked on 24 October 2026. See the current price on Apify.

Questions

Can I search by title?

No. You need the DOI.

Does it give abstracts or PDFs?

No. It gives bibliographic metadata only.

Why is a date only a year?

The tool keeps the source precision. It does not add a fake day.

Why is my citation count lower than Google Scholar?

It is the count from Crossref or DataCite. Other indexes count other sources.

Do I need an API key?

No. Crossref, DataCite, JaLC and doi.org are open. You only need your Apify account.

Why is citedByCount different from Google Scholar?

It is the count known to the registration agency (Crossref or DataCite). Other indexes count different sources.

How fresh is the data?

Each run reads the sources live. Each row has fetchedAt (our read time) and sourceUpdatedAt (when the agency last updated the record).

Details

Step by step on Apify
  1. Open the Input tab.
  2. Keep the three example DOIs in DOIs (dois) or paste your own, one per line.
  3. Leave Contact email empty, or add your own email for large runs.
  4. Click Start.
  5. Open the Output tab, view Citations. Check status and title in the first row.
Use cases
TaskInputYou getKey fieldsNext step
Build a reference tabledoisOne citation record per DOItitle, authors, containerTitle, issuedDate, pagesExport CSV/Excel, or read the Dataset by API
Clean a bibliographydoisStatus per DOIstatus, statusReason, errorCode, doiFilter rows where status is not complete
Enrich a paper listdoisIdentifiers and countsissn, isbn, publisher, licenses, citedByCountJoin on doi (always lower case)
Catalogue research datadoisDataCite dataset recordresourceTypeGeneral, publisher, publicationYear, languageExport or API
Tips for better results
  • Paste DOIs in any form, like doi: or a doi.org link.
  • Filter rows that are not complete to clean your list.
  • Join on the DOI column. It is always lower case.
Limits and good to know
  • Up to 500 DOIs per run. In tests, 500 DOIs finished in about 24 seconds and 100 DOIs in about 6 seconds
  • The Actor reads sources for up to 240 seconds. DOIs not processed in time get a free error row with DEADLINE_REACHED
  • It sends batch requests (up to 50 DOIs each) and retries temporary failures. It respects source rate limits

Troubleshooting

SymptomCheckAction
not_found for a DOI you trustinput, doiLook for a typo or extra characters. doi.org itself says the DOI is not registered.
invalid rowinput, statusReasonAfter cleaning, the value is not in the form 10.<prefix>/<suffix>. Fix the value.
partial with RECORD_NOT_INDEXEDstatusReasonThe DOI is registered, but the agency API does not have the record yet. Try again later.
partial with NO_TITLEtypeRecords such as journal issues or figures often have no title. This is source data.
unsupported_agencyagencyThe DOI belongs to another agency. This Actor does not read its metadata.
error rowserrorCode, RUN_SUMMARY.warningsA source was down or slow. Run only these DOIs again later; they were not charged.
Run rejected at startInputdois is empty or has more than 500 values.

For developers

Sample result

One result from a real test run, in JSON. Real values change from run to run. In Excel or CSV each field is a column.

one result · JSON
{
  "input": "10.1038/nature12373",
  "doi": "10.1038/nature12373",
  "doiUrl": "https://doi.org/10.1038/nature12373",
  "status": "complete",
  "statusReason": null,
  "agency": "Crossref",
  "type": "journal-article",
  "title": "Nanometre-scale thermometry in a living cell",
  "authors": [
    { "given": "G.", "family": "Kucsko", "name": "G. Kucsko", "orcid": null, "affiliations": [] }
  ],
  "containerTitle": "Nature",
  "publisher": "Springer Science and Business Media LLC",
  "issuedDate": "2013-07-31",
  "publishedPrintDate": "2013-08",
  "publicationYear": 2013,
  "volume": "500",
  "issue": "7460",
  "pages": "54-58",
  "issn": [
    { "value": "0028-0836", "type": "print" },
    { "value": "1476-4687", "type": "electronic" }
  ],
  "authorsCount": 8,
  "provider": "Crossref REST API",
  "errorCode": null
}

Use it from code

Actor ID: cliqtomedia/doi-bibliography-enrichment. You need your Apify API token from Apify Console → Settings → API & Integrations.

Python · apify-client
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/doi-bibliography-enrichment").call(run_input={
    "dois": [
        "10.1038/nature12373",
        "10.5061/dryad.8515",
        "10.1007/978-3-319-24277-4_9"
    ]
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
cURL
curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~doi-bibliography-enrichment/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"dois": ["10.1038/nature12373", "10.5061/dryad.8515", "10.1007/978-3-319-24277-4_9"]}'
LangChain · langchain-apify
# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("cliqtomedia/doi-bibliography-enrichment")
result = tool.invoke({"run_input": {"dois": ["10.1038/nature12373", "10.5061/dryad.8515", "10.1007/978-3-319-24277-4_9"]}})
print(result)

The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.

Data fields (37)
FieldTypeMeaning
inputstringYour input value exactly as given.
doistringCanonical DOI in lower case (DOIs are case-insensitive); null for invalid input.
doiUrlstringResolvable https://doi.org/ link.
statusstringcomplete: metadata found. partial: DOI exists but the record is missing or has no title. not_found: doi.org says the DOI is not registered. invalid: not a DOI. unsupported_agency: registered with another agency (agency is given). error: a source failed; existence unknown.
statusReasonstringPlain-English explanation for any status other than complete.
agencystringRegistration agency from doi.org: Crossref, DataCite, JaLC, mEDRA, …
typestringWork type as the agency names it, e.g. journal-article, book-chapter, proceedings-article, dataset.
resourceTypeGeneralstringDataCite general resource type, e.g. Dataset, Software, Text.
titlestringTitle with markup removed and HTML entities decoded.
subtitlestringSubtitle, if the record has one.
authorsarrayAuthors in record order: given, family, full name, ORCID URL (only when the source lists it), affiliations.
editorsarrayEditors, same shape as authors.
containerTitlestringJournal, book or proceedings that contains the work (for a book chapter, the book).
containerTitlesarrayAll container titles exactly as the agency lists them.
seriesTitlestringBook series, e.g. Use R!, when the record lists one.
publisherstringPublisher.
issuedDatestringPublication date at the precision the source gives: 2016, 2013-08 or 2013-07-31. Never padded.
publishedOnlineDatestringOnline publication date (Crossref), same precision rule.
publishedPrintDatestringPrint publication date (Crossref), same precision rule.
publicationYearintegerPublication year.
volumestringVolume.
issuestringIssue.
pagesstringPage range, e.g. 54-58.
articleNumberstringArticle number for journals without page numbers.
issnarrayISSNs with type print/electronic when known.
isbnarrayISBNs with type print/electronic when known.
licensesarrayLicense statements from the record (Crossref license / DataCite rightsList).
referencesCountintegerNumber of references deposited with the record.
citedByCountintegerCitations known to the agency (Crossref is-referenced-by-count / DataCite citationCount).
languagestringLanguage code when the record states it (DataCite, JaLC; not returned by Crossref batch queries).
landingUrlstringPublisher landing page registered for the DOI.
sourceUpdatedAtstringWhen the agency last indexed or updated the record.
authorsCountintegerNumber of authors.
providerstringAPI the row came from.
sourceUrlstringAPI request the metadata was read from.
fetchedAtstringWhen this row was produced (ISO 8601).
errorCodestringMachine code: INVALID_DOI, DOI_NOT_REGISTERED, UNSUPPORTED_AGENCY, RECORD_NOT_INDEXED, NO_TITLE, SOURCE_UNAVAILABLE, RATE_LIMITED, DEADLINE_REACHED, …
Input settings (2)

The main fields of the input form. With the API you send them as JSON.

SettingName in the APITypeExample value
DOIs requireddoisarray["10.1038/nature12373", "10.5061/dryad.8515", "10.1007/978-3-319-24277-4_9"]
Contact email for Crossref and DataCite (optional)contactEmailstring

Start on Apify

Make a free Apify account: you get $5 of free usage every month. Missing a tool? Suggest it. We read every idea, but we do not promise to build it.

Apify links on this page are affiliate links. We may earn a commission. You pay the same price. Affiliate disclosure