# Crossref DOI Lookup — Canonical Citation Metadata API (`accountable_eel/crossref-doi-lookup`) Actor

Look up DOIs against Crossref's official metadata API — the canonical source publishers register citation data with. Get title, full author list with ORCID and affiliation, journal, publisher, ISSN, license, and reference/citation counts. Pay only for DOIs that resolve.

- **URL**: https://apify.com/accountable\_eel/crossref-doi-lookup.md
- **Developed by:** [Adrian Voss](https://apify.com/accountable_eel) (community)
- **Categories:** Developer tools, Education
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 successful lookups

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Crossref DOI Lookup

Look up any DOI against [Crossref](https://www.crossref.org)'s official metadata
API — the canonical registration agency publishers submit citation data to. Get title,
full author list (with ORCID and affiliation when registered), journal, publisher, ISSN,
license, and reference/citation counts. No API key, no scraping — this hits the official
public API directly.

### Features

- **DOI → full citation record.** Title, work type, publisher, journal/container title,
  ISSN, published date, volume, issue, page range.
- **Full author list.** Name, ORCID, and affiliation for every listed author, not just
  the first.
- **Citation metrics.** Reference count (works this DOI cites) and cited-by count
  (works citing this DOI, as tracked by Crossref).
- **Pay only for hits.** DOIs that don't resolve cost nothing — see [Pricing](#pricing).
- **One row per DOI or per author.** Optionally expand each author into its own output
  row without paying more.

### How to use Crossref DOI Lookup — Canonical Citation Metadata API

1. **In the Apify Console.** Open the actor page and click **Start** — the `dois` field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
2. **Via the API.** Call it directly with a POST request — no Console needed once you have an API token:
   ```bash
   curl "https://api.apify.com/v2/acts/accountable_eel~crossref-doi-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"dois":["10.1038/nature12373"]}'
   ```
3. **On a schedule.** Save this actor as an Apify **Task** with the input you want, then add a **Schedule** (hourly, daily, weekly) so it runs on its own — no server of your own required.

### Input

```json
{
  "dois": [
    "10.1038/nature12373"
  ]
}
```

One DOI or doi.org URL per line. Accepted formats: 10.1038/nature12373, https://doi.org/10.1038/nature12373.

```json
{
  "dois": ["10.1038/nature12373"],
  "testRun": false,
  "onlyFound": false,
  "expandRows": false,
  "maxConcurrency": 5
}
```

`dois` is a list of DOIs, accepted either as a bare DOI (`10.1038/nature12373`) or a
`doi.org` URL — the actor extracts the DOI pattern automatically. One dataset row is
returned per DOI; rows with `"found": false` are never charged. Turn on `testRun` to try
your list against just the first 5 DOIs before running the full batch. Turn on
`expandRows` to get one row per author instead of one row per DOI — you're still only
charged once per DOI no matter how many author rows it produces. Optional
`includeKeywords` / `excludeKeywords` filter rows by content, `maxResults` caps the run
early, and `columns` lets you pick which fields to return.

### Output

| query | found | status | title | doi | type | publisher | journal | issn | publishedDate | volume | issue | page | referenceCount | isReferencedByCount | license | authors | authorCount | url | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 10.1038/nature12373 | true | OK | Nanometre-scale thermometry in a living cell | 10.1038/nature12373 | journal-article | Springer Science and Business Media LLC | Nature | 0028-0836 | 2013-7-31 | 500 | 7460 | 54-58 | 30 | 1806 | http://www.springer.com/tdm | \[{"name":"G. Kucsko","orcid":null,"affiliation":null},{"name":"P. C. Maurer","orcid":null,"affiliation":null},{"name":"N. Y. Yao","orcid":null,"affiliation":null},{"name":"M. Kubo","orcid":null,"affiliation":null},{"name":"H. J. Noh","orcid":null,"affiliation":null},{"name":"P. K. Lo","orcid":null,"affiliation":null},{"name":"H. Park","orcid":null,"affiliation":null},{"name":"M. D. Lukin","orcid":null,"affiliation":null}] | 8 | https://doi.org/10.1038/nature12373 | 2026-08-23T21:03:06.962Z |

One row per DOI, for example:

```json
{
  "query": "10.1038/nature12373",
  "found": true,
  "status": "OK",
  "doi": "10.1038/nature12373",
  "title": "A mesoscale connectome of the mouse brain",
  "type": "journal-article",
  "publisher": "Springer Science and Business Media LLC",
  "journal": "Nature",
  "issn": "0028-0836",
  "publishedDate": "2014-1",
  "volume": "508",
  "issue": "7495",
  "page": "207-214",
  "referenceCount": 45,
  "isReferencedByCount": 1382,
  "license": "https://www.springer.com/tdm",
  "authors": [
    { "name": "Seung Wook Oh", "orcid": null, "affiliation": "Allen Institute for Brain Science" }
  ],
  "authorCount": 12,
  "url": "http://dx.doi.org/10.1038/nature12373",
  "scrapedAt": "2026-08-21T10:00:00.000Z"
}
```

DOIs that don't resolve still get a row (`"found": false`, `"status": "NOT_FOUND"`, with
a plain-English `message`), so you always get one row per input — but you're never
charged for those.

### Use cases

- **Reference list enrichment** — turn a bare list of DOIs from a bibliography or
  citation manager into full title/author/journal metadata.
- **Citation impact tracking** — pull `isReferencedByCount` in bulk to monitor how a set
  of papers is being cited over time.
- **Author & affiliation mapping** — expand rows per author to build an
  author-to-institution dataset from a corpus of DOIs.
- **Publisher & license auditing** — check `publisher` and `license` across a
  collection to confirm open-access or reuse terms.

### Pricing

$4 per 1,000 DOIs, plus a $0.005 start fee. Misses (`found:false`) are never charged.

### Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

```bash
curl "https://api.apify.com/v2/acts/accountable_eel~crossref-doi-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"dois":["10.1038/nature12373"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~crossref-doi-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"dois":["10.1038/nature12373"]}` (swap in an expression from an earlier node for a real value).

**Clay.** Add an "HTTP API" column: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~crossref-doi-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body `{"dois":["{{DOI}}"]}`, mapping the row's DOI into the `dois` array.

**MCP.** In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Crossref API — DOI to Citation Metadata" — the agent will find and run this actor.

### FAQ

**Do I need a Crossref API key?**
No. The Crossref REST API is free and public — this actor calls it directly, with no
credentials required on your end.

**What counts as "not found"?**
A well-formed DOI with no Crossref record returns `"found": false"` with `"status":
"NOT_FOUND"`. Crossref only covers works registered with it as the DOI registration
agency — DOIs registered elsewhere (e.g. DataCite) will also come back as not found.

**Can I paste a doi.org URL instead of a bare DOI?**
Yes. The actor extracts the `10.xxxx/...` pattern from whatever you paste, so
`https://doi.org/10.1038/nature12373`, a bare DOI, or a DOI with trailing punctuation
all normalize to the same lookup.

**Are all authors always registered with ORCID and affiliation?**
No — `orcid` and `affiliation` are only populated when the publisher included them in
the Crossref submission. Many records only have author names. Author order matches
Crossref's own listing.

**Can I get one row per author instead of one row per DOI?**
Yes — turn on `expandRows`. Each author becomes its own dataset row, but billing is
still per DOI found, not per author row.

**Can I run this against thousands of DOIs at once?**
Yes. Turn on `testRun` first to sanity-check your list against just 5 DOIs, then run the
full batch — `maxConcurrency` controls how many requests run in parallel.

# Actor input Schema

## `dois` (type: `array`):

One DOI or doi.org URL per line. Accepted formats: 10.1038/nature12373, https://doi.org/10.1038/nature12373. You're only charged for the ones we actually find — a miss costs nothing.

## `testRun` (type: `boolean`):

Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.

## `onlyFound` (type: `boolean`):

Only keep rows where something was actually found. Misses are always free, whether or not you show them here.

## `includeKeywords` (type: `array`):

Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.

## `maxResults` (type: `integer`):

Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit.

## `columns` (type: `array`):

Choose which pieces of information to include in each result row. All are included by default.

## `expandRows` (type: `boolean`):

When on, each author found gets its own row instead of being grouped under its DOI. You're still only charged once per DOI, no matter how many rows it produces.

## `maxConcurrency` (type: `integer`):

Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.

## `proxyConfiguration` (type: `object`):

Apify Proxy config. Residential recommended for anti-bot-sensitive targets.

## Actor input object example

```json
{
  "dois": [
    "10.1038/nature12373"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "columns": [
    "title",
    "doi",
    "type",
    "publisher",
    "journal",
    "issn",
    "publishedDate",
    "volume",
    "issue",
    "page",
    "referenceCount",
    "isReferencedByCount",
    "license",
    "authors",
    "authorCount",
    "url"
  ],
  "expandRows": false,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "dois": [
        "10.1038/nature12373"
    ],
    "includeKeywords": [],
    "excludeKeywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/crossref-doi-lookup").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "dois": ["10.1038/nature12373"],
    "includeKeywords": [],
    "excludeKeywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/crossref-doi-lookup").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "dois": [
    "10.1038/nature12373"
  ],
  "includeKeywords": [],
  "excludeKeywords": []
}' |
apify call accountable_eel/crossref-doi-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,accountable_eel/crossref-doi-lookup"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/V22Zy5wfwlrCHsc0o/builds/UXGAbTjN8q7XySRTY/openapi.json
