# New Scholarly Papers Watch (Crossref, OpenAlex) (`lone_rachis/scholarly-papers-watch`) Actor

Saved watches for new scholarly papers from Crossref: keywords, ORCID iDs, journals, funders, and institutions with your OpenAlex key. Each run returns only works it did not deliver before, and flags retractions, corrections and citation changes for your DOIs.

- **URL**: https://apify.com/lone_rachis/scholarly-papers-watch.md
- **Developed by:** [Kesav Kumar Jayakumar](https://apify.com/lone_rachis) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 paper scrapeds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does New Scholarly Papers Watch do?

**New Scholarly Papers Watch** keeps saved watches over Crossref, the registry where publishers deposit the DOIs and metadata of journal articles, preprints, conference papers, book chapters and datasets. You list what to watch, and each run delivers only the works it did not deliver before. A watch can be:

- **query:** keywords, matched with every word in the title, subtitle or abstract.
- **author:** an ORCID iD.
- **journal:** an ISSN.
- **funder:** a Crossref funder ID, such as the one of a research council.
- **affiliation:** a ROR ID for an institution, read from OpenAlex with your own OpenAlex key.
- **doi:** a list of DOIs whose update notices (retraction, correction, expression of concern, new version) and cited-by count are watched.

Each row is one work with its DOI, title, type, journal or server, publisher, dates, authors with their ORCID iDs and affiliations, funders and awards, licence, reference and cited-by counts, and the update notices that point at it. The first run of a watch delivers its newest works as a baseline. Later runs deliver only what is new, and a run with nothing new writes one free row that says so.

The Actor reads Crossref's public REST API, which needs no key, and keeps to the rate Crossref announces in its answers. OpenAlex is used only when you give your own key. Rows keep author names and ORCID iDs as the record shows them, but never an email address and never the abstract. **The Actor is not affiliated with Crossref or OpenAlex.**

### Why use New Scholarly Papers Watch?

Keeping up with a field means running the same searches every week and working out which results you have seen. A database alert covers one database and one search at a time, and a retraction of a paper you cite usually reaches you late, if at all. This Actor keeps every watch in one input, remembers what it delivered, and on a schedule sends only what is new.

What you get:

- **Six kinds of watch in one input.** Up to 50 watches a run, mixing keywords, ORCID iDs, ISSNs, funder IDs, ROR IDs and DOI lists, each with an optional label and a published-since date.
- **Only what is new.** After a watch's first run, a work is new when its DOI was registered with Crossref after that first run began and no watch of the memory has delivered it. Later runs also look back 7 days for works Crossref showed late. Each work is delivered once per memory, under the first watch that finds it, so a paper that matches three of your watches costs one row.
- **Retractions and corrections for your DOIs.** A doi watch delivers a DOI again when Crossref shows a new update notice pointing at it, or when its cited-by count moved, with each change's old and new value.
- **Every-word keyword matching.** Crossref's search ranks any-word matches. The Actor keeps only works that hold every one of your words, "quoted phrases" and `word*` prefixes included.
- **No key needed.** Crossref is free to read. Your OpenAlex key is optional and adds affiliation watches, open-access links and the authors' ROR IDs.

Each claim above has a test behind it:

| What you get | How it works | The test that backs it |
| --- | --- | --- |
| **Keyword watches with an every-word rule** | Stop words are ignored, accents and punctuation removed, and every remaining word must appear in the title, subtitle or abstract. On a busy topic, where half the first page or more holds every word, the Actor reads newest first. On a sparse topic it reads up to 5 pages by score and keeps the newest matches. | "query filter: every term must be present; a phrase needs its words in a row; a prefix matches word starts", "query filter, dense topic: half or more of the first page matches, so it reads newest first and keeps only full matches", "query filter, sparse topic: it reads by score until a page has no full match, then delivers the newest matches". Checked by hand against the raw Crossref API on 13 Oct 2026 for "CRISPR base editing". |
| **Author, journal and funder watches** | Crossref's own filters on ORCID iD, ISSN and funder ID, sorted by registration date. Each ID is checked before any request: the ORCID and ISSN check characters, the funder DOI prefix and the ROR check digits. | "author, journal and funder filters: orcid:, issn: and funder:, plus from-pub-date when since is set", "an ORCID watch delivers the author's newest works, each listing that ORCID iD", "ORCID: the ISO 7064 11,2 check character, X included". The ORCID watch was checked by hand against the raw API on 13 Oct 2026: the same five DOIs in the same order. |
| **Only what is new** | After the first run, the watch's floor is the time that run began, so nothing registered before it is ever delivered as new, even what the first run's cut at `maxPerWatch` held back or a relevance read did not reach. A later run reads from its last check minus 7 days, never below the floor, for works Crossref shows late, and skips every DOI the memory holds. | "regression: a capped baseline read by relevance, then a run five minutes later delivers 0; a work registered after the baseline is still new", "a later run reads from the last check minus 7 days, skips what any watch delivered, and stops at the floor", "dedupe: the same work twice in one answer is delivered once, and a work removed on request is never delivered", "the prefill: the first run delivers each watch's baseline, the second delivers and charges nothing, the third delivers only the added watch", and the live test "live: the prefill delivers 10 newest works per watch; a second run on the same memory delivers only works registered since, charging only those". |
| **Retractions and corrections for your DOIs** | Up to 200 DOIs per watch, read 25 to a request. The memory keeps each DOI's notices and cited-by count, and a run delivers the DOI again only when one of them moved. | "update rule: a new notice (retraction, correction, expression of concern, new version) is a change with old empty", "a DOI whose correction appears between runs is delivered again, with the new notice in its changes", "a DOI whose cited-by count rose is delivered again with the old and new count; a retraction gains no row when nothing moved". The Wakefield paper's two notices were checked by hand against the raw API on 13 Oct 2026. |
| **A memory with a known size** | Each watch remembers the newest 5,000 works it delivered. Older ones drop off, and the watch's floor moves past them so they cannot come back as new. | "dedupe: the seen set keeps the newest 5,000 by default and raises the floor past the ones it drops", "memory store names: the same watches give the same name in any order; a saved task keeps one name". |
| **Inside Crossref's rate limit** | The Actor reads the rate Crossref announces in every answer (1 request a second on 14 Oct 2026) and keeps a little under it. A 429 answer (too many requests) is waited out for its Retry-After time, or 60 seconds, and three in a row stop the run. | "Crossref pacing: starts are 1.25 times the announced gap apart, and the gap follows the headers", "a 429 is waited out and the run still delivers everything; the summary counts it", "three 429s in a row stop the run before anything is delivered; it fails, with one free row naming the cause", "a 5xx is retried and the run goes on; a watch that keeps failing is a free failed row and the next run tries it again". |
| **OpenAlex only with your key** | Without `openAlexApiKey` the Actor sends OpenAlex nothing, and the run summary says so. With it, the run stops asking OpenAlex at your request cap or when the key's daily allowance runs low, and the Crossref watches carry on. | "without a key: no request goes to OpenAlex, an affiliation watch is a free skipped row, and the summary says OpenAlex was not used", "the request cap and a spent allowance stop OpenAlex and skip the affiliation watch, never the run", "the OpenAlex key is never written to the dataset, the stores or the log". |
| **Your contact email stays private** | When you give `contactEmail`, it goes only into the User-Agent header of requests to Crossref, as Crossref's polite pool asks. | "the contact email goes in the User-Agent of every Crossref request and nowhere else: not the dataset, the stores or the log". |
| **No abstracts and no email addresses** | The abstract is read only to match keywords and never written. Email addresses are removed from every text field. | "no abstract and no email address ever leaves a work, whatever the record holds". |
| **Charged only for what you get** | One charge per row with status `ok`. Every other row is free, and the run stops before it would charge past your maximum cost per run. A run that restarts reads its own rows first. | "C1 the maximum cost per run stops delivery cleanly, and the next run delivers what was held back, charging nothing twice", "B2 a crash after a row is written but before the memory is saved delivers and charges nothing twice", "an empty result: a keyword watch that matches nothing gives one free row and no charge". |

Plus what the Apify platform adds around it:

- **API access.** Start runs and read results with the Apify API or the JavaScript and Python clients.
- **Scheduling.** Run the watch every Monday morning and get only what appeared that week.
- **Integrations.** Send rows to Make, Zapier, Google Sheets, Slack or any webhook.
- **Monitoring.** Run history, logs and alerts for failed runs.

Typical uses are a weekly reading list for a lab, an alert on new papers by the people you follow, a feed of what a journal or a funder's grants produced this week, a check that nothing you cite has been retracted, and a count of how the citations of your own papers move.

### What data can New Scholarly Papers Watch extract?

Each work becomes one row in the dataset. The most useful fields:

| Field | Type | What it holds |
| --- | --- | --- |
| `status` | string | `ok`, `not-found`, `invalid`, `failed`, `skipped`, `removed` or `no-new-works`. |
| `watchId`, `watchType`, `watchLabel`, `watchValue` | string | The watch that found the work: its ID, type, your label, and what it looks for. For a doi watch, `watchValue` is the row's DOI. |
| `changeType`, `changes` | string, array | `baseline` (the watch's first run), `new`, or `changed` for a DOI with a new notice or cited-by count, and one `{ field, old, new }` per change. |
| `doi`, `doiUrl` | string | The DOI in lower case, and its https://doi.org/ link. |
| `title`, `subtitle`, `type` | string | The title and subtitle as deposited, and Crossref's type, such as `journal-article`, `posted-content` (a preprint), `proceedings-article`, `book-chapter` or `dataset`. |
| `containerTitle`, `issn`, `publisher` | string, array, string | The journal, book, proceedings or preprint server, its ISSNs, and the publisher. |
| `publishedDate`, `publishedPrint`, `publishedOnline` | string | The earliest publication date, and the print and online dates, as YYYY, YYYY-MM or YYYY-MM-DD. |
| `registeredAt`, `indexedAt` | string | When the DOI was first registered with Crossref, which is what new means here, and when Crossref last re-indexed the record. |
| `authors`, `authorCount`, `authorsTruncated`, `firstAuthor` | array, integer, boolean, string | Up to 100 authors in order, each with name, given and family name, ORCID iD and whether it was authenticated, affiliations, ROR IDs (with your OpenAlex key) and sequence. Never an email address. |
| `funders` | array | Funder name, Crossref funder ID and award numbers. |
| `licenceUrls`, `openAccessUrl`, `openAccessStatus` | array, string, string | Licences as deposited, and a free full-text link with OpenAlex's open-access status (with your OpenAlex key). |
| `referenceCount`, `citedByCount` | integer | How many works this one cites, and how many Crossref works cite it. |
| `subjects` | array | Subject terms as Crossref holds them, often empty. For affiliation rows, OpenAlex topics. |
| `updates`, `retracted` | array, boolean | Notices that point at the work: type, label, notice DOI, date and source (`publisher` or `retraction-watch`, for example), and whether one of them is a retraction, partial retraction, withdrawal or removal. |
| `source`, `openAlexId` | string | `crossref`, or `openalex` for affiliation rows, and the OpenAlex work ID when your key was used. |
| `stateStore`, `checkedAt` | string | The memory's store name, and when the row was written. |
| `error`, `errorCode` | string | Why a row is not `ok`, as a sentence and as a short code. |

The **Overview** view shows the watch, title, journal, dates, first author, cited-by count, retraction flag and DOI link. The **Authors and funders** view shows the authors with their ORCID iDs, the funders and the open-access link. The **DOI changes** view shows what moved for the DOIs you watch.

Every row that is not `ok` carries one of these codes in `errorCode`, so you can count rows by reason without reading the sentence. The sentence in `error` can be reworded in a later version. The code stays.

| `errorCode` | Meaning |
| --- | --- |
| `not-found` | Crossref has no record of a DOI in a doi watch. It may be registered with another agency. Said once; later runs count it in the summary. |
| `invalid-watch` | A watch that could not be read, such as an ORCID iD with a wrong check character or a query with no usable word. |
| `invalid-doi` | An entry in a doi watch that is not a DOI. |
| `duplicate-watch` | The same watch is already in your list, so it was checked once. |
| `removed-on-request` | The work was removed from this Actor's output on request. |
| `no-new-works` | A run in which no watch had anything new. |
| `max-per-watch` | A later run found more new works than `maxPerWatch`. The newest were delivered and the older ones left out for good. |
| `openalex-key-needed` | An affiliation watch, which reads OpenAlex, with no OpenAlex key in the input. |
| `key-refused` | OpenAlex did not accept the key in `openAlexApiKey`. |
| `openalex-plan` | OpenAlex said the request needs a paid plan. |
| `openalex-budget` | Your OpenAlex key had too little of its daily allowance left for another request. |
| `openalex-limit` | The run reached `openAlexMaxRequests`. |
| `charge-limit` | The run reached your maximum cost per run. |
| `run-time-limit` | The run reached its time limit. |
| `rate-limited` | Crossref or OpenAlex answered "too many requests" (HTTP 429) three times in a row. |
| `repeated-failures` | Five watches in a row failed with a server or network error, so the run stopped. |
| `aborted` | The run was stopped. |
| `bad-request` | Crossref did not accept the request (HTTP 400). Its reason is in `error`. |
| `server-error`, `http-error` | The API answered with an error status. |
| `network-error`, `timeout` | The API could not be reached, or did not answer within 30 seconds. |
| `too-large`, `bad-response`, `unexpected-redirect` | An answer over 20 MB, an answer the Actor could not read, or a redirect to another site. |
| `other` | Any other reason. The sentence in `error` says what happened. |

### How to watch for new scholarly papers by keyword, author, journal or funder

1. Open the Actor in Apify Console and select the **Input** tab.
2. The form is prefilled with two keyword watches (large language models, CRISPR base editing) and one ORCID iD (Jennifer Doudna) at 10 works each, so you can press **Start** to see a result straight away. The run takes about 11 seconds and delivers 30 works.
3. Edit **Watches** (`watches`). Each watch is one object with a `type`:
   - `{ "type": "query", "keywords": "CRISPR base editing" }`, with `"titleOnly": true` to match titles only.
   - `{ "type": "author", "orcid": "0000-0002-1825-0097" }`
   - `{ "type": "journal", "issn": "1476-4687" }`
   - `{ "type": "funder", "funderId": "10.13039/100000001" }`
   - `{ "type": "affiliation", "ror": "03vek6s52" }`, which needs an OpenAlex key.
   - `{ "type": "doi", "dois": ["10.1016/s0140-6736(97)11096-0", "10.1038/nature12373"] }`
   - Any watch can take a `label`, and every type but doi a `since` date such as `"2026-01-01"`.
4. Set **Most works per watch per run** (`maxPerWatch`). The first run of a watch delivers its newest works up to this number, and so do later runs when a lot is new.
5. Optional: put your email address in **Your email for Crossref** (`contactEmail`). Crossref asks API users for a contact address and sends such requests to its polite pool.
6. Save the input as a task, or set **Watch memory name** (`stateStoreName`), such as `my-lab-watch`. Either way a watch you add later brings only its own baseline.
7. Optional, for affiliation watches and open-access links: add your own OpenAlex API key in **Your OpenAlex API key** (`openAlexApiKey`). Create a free account on the OpenAlex website, open your account settings, and copy the API key shown there. These steps were written from OpenAlex's own description and were not followed while building the Actor, so the pages may look different.
8. Press **Start**. Open the **Output** tab for the table, and export it as JSON, CSV or Excel. Then create a schedule with the same input, for example every Monday at 7:00.

To run it from code, send the same input to the Actor through the API:

```json
{
    "watches": [
        { "type": "query", "keywords": "\"single-cell\" RNA sequencing", "label": "scRNA-seq" },
        { "type": "author", "orcid": "0000-0001-9161-999X", "label": "Jennifer Doudna" },
        { "type": "journal", "issn": "1476-4687", "label": "Nature" },
        { "type": "doi", "dois": ["10.1016/s0140-6736(97)11096-0"], "label": "Papers we cite" }
    ],
    "maxPerWatch": 20,
    "stateStoreName": "my-lab-watch"
}
```

### How to send new papers to Slack or Google Sheets (Make, Zapier, no code)

After the first run, a scheduled watch holds only the works that are new since the last run, so you can pass every run's results straight on.

**Slack, built in.** On the Actor's **Integrations** tab, add **Slack**, connect your workspace, pick a channel and choose the event "Run succeeded". Each finished run posts a message with a link to its results.

**Google Sheets with Make.com.**

1. In Make, create a scenario and add the Apify module that watches for finished Actor runs, set to this Actor.
2. Add the Apify module that gets dataset items, and map the run's default dataset ID.
3. Add Google Sheets "Add a Row" and map the fields you want, for example `watchLabel`, `title`, `containerTitle`, `publishedDate`, `firstAuthor`, `doiUrl` and `changeType`.
4. Optional: add a filter so only rows with `status` `ok` reach the sheet, or only rows where `retracted` is true.

**Google Sheets or Slack with Zapier.** Use the Apify trigger for a finished Actor run, then the Apify step that fetches dataset items, then a Google Sheets "Create Spreadsheet Row" or a Slack "Send Channel Message" action. A Zapier filter step works the same way as the Make filter.

**Your own code.** Add a webhook on the **Integrations** tab for the event "Run succeeded", and read the dataset from the URL in the payload.

Set the schedule first (see the steps above), so that each run, and each message or row, covers what is new since the run before.

### How much does it cost to watch new scholarly papers?

You pay per work delivered, and the Apify platform usage for the run is included. A work costs $0.005 on the Free and Bronze plans, so 1,000 works cost $5.

| Event | When it is charged | Price |
| --- | --- | --- |
| `paper` | One work or DOI row delivered with status `ok`: each work of a watch's first-run baseline, each new work after that, each DOI of a doi watch on its first run, and each DOI that changed | $0.005 (Free, Bronze), $0.0045 (Silver), $0.004 (Gold) |
| Actor start | Once per run, scaled by memory (Apify standard event) | $0.00005 per GB of memory |

Rows with the status `not-found`, `invalid`, `failed`, `skipped`, `removed` or `no-new-works` cost nothing, and a work found by two watches is charged once. You can cap a run with the **Maximum cost per run** setting, and the Actor stops cleanly at that limit.

#### How much does one paper cost?

One work costs $0.005 on the Free and Bronze plans, $0.0045 on Silver and $0.004 on Gold. A run adds a start fee of about $0.0000125 at the default memory of 256 MB. As a guide: 20 watches at the default of 50 works each start with a baseline of up to 1,000 works, $5.00 at most (a measured run of 20 such watches delivered 652, $3.26). With about 15 new works a week after that, a month of weekly runs adds about $0.30. With `maxPerWatch` at 10, the baseline is at most 200 works, $1.00.

#### How do I keep a run within budget?

Set **Maximum cost per run** when you start it or in the schedule. The run stops before it would charge past that amount, and the watches it did not finish get one free `skipped` row with the code `charge-limit`. Those works stay out of the memory, so the next run delivers them. A lower `maxPerWatch` and a `since` date keep the first-run baseline small.

#### What does a run cost when nothing is new?

Only the start fee, about $0.0000125 at 256 MB. The run writes one `no-new-works` row and charges nothing for it.

#### Do I need an OpenAlex key?

No. Every watch type except affiliation works without one, and the price is the same either way. A key adds affiliation (ROR) watches, an open-access link and status for each work, and the authors' ROR IDs. OpenAlex counts each request against your key's daily allowance, not against Apify, and the Actor sends at most `openAlexMaxRequests` requests a run (50 by default).

### Input

Open the **Input** tab to see every setting with a short description. Only `watches` is required. The form has four groups:

- **Watches:** `watches` and `maxPerWatch`.
- **Crossref:** `contactEmail`.
- **Watch memory:** `stateStoreName`.
- **OpenAlex (optional):** `openAlexApiKey`, a secret field, and `openAlexMaxRequests`.

`watches` takes up to 50 watches. The fields of a watch:

| Field | For | What it holds |
| --- | --- | --- |
| `type` | every watch | `query`, `author`, `journal`, `funder`, `affiliation` or `doi`. |
| `label` | every watch | Optional. A name copied into each of the watch's rows. |
| `keywords`, `titleOnly` | query | The words to match, and whether to look in titles and subtitles only. |
| `orcid` | author | An ORCID iD, with or without https://orcid.org/. |
| `issn` | journal | An ISSN, print or electronic. |
| `funderId` | funder | A Crossref funder ID, as 10.13039/100000001 or the number alone. |
| `ror` | affiliation | A ROR ID, with or without https://ror.org/. |
| `dois` | doi | Up to 200 DOIs, bare or as doi.org links. |
| `since` | every type but doi | Optional. Only works published on or after this date, written YYYY-MM-DD. |

`maxPerWatch` is 50 by default and at most 1,000. A watch's first run delivers its newest works up to this number. A keyword watch's first run looks back 30 days, and an author, journal or funder watch's first run takes its newest works by registration date, however old. When a later run finds more new works than `maxPerWatch`, the newest are delivered, the older ones are left out for good, and a free row says how many.

`contactEmail` is optional. It is sent only in the User-Agent header to Crossref and is never logged or stored.

`stateStoreName` names the key-value store that remembers what each watch delivered. With a name, an added watch delivers only its own baseline, and a removed watch is simply no longer checked. Left empty, a run of a saved task keeps one memory for that task, which works the same way. A run outside a task and without a name keeps a memory named after its watches, so adding or changing a watch there starts a new memory, and the next run delivers (and charges) every watch's baseline again.

`openAlexApiKey` is your own OpenAlex key. Without it the Actor never calls OpenAlex. `openAlexMaxRequests` caps the requests a run sends OpenAlex, 50 by default, and 0 turns OpenAlex off.

### Output

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. A run also writes a `SUMMARY` record to its key-value store with the counts of watches checked and delivered as a baseline, works delivered as a baseline and as new, DOI rows (baseline and changed), works found again but delivered before, works held back by `maxPerWatch`, DOIs not found, invalid, failed, skipped and removed rows, the charged rows, the reason the run stopped early if it did, the memory's name and size, whether the polite pool was used (never the address), the Crossref requests, retries, 429 answers and the rate it announced, what OpenAlex was used for and what it cost your key, and one line per watch. A run in which no watch could be checked ends with the status Failed and the reason in its message, and the rows stay in the dataset.

A keyword watch's work, a cited paper with its two notices, and a DOI Crossref does not hold look like this:

```json
[
    {
        "status": "ok",
        "errorCode": null,
        "error": null,
        "watchId": "908294479c759e788fac",
        "watchType": "query",
        "watchLabel": "Base editing",
        "watchValue": "CRISPR base editing",
        "changeType": "baseline",
        "changes": [],
        "doi": "10.63721/25jbasr0105",
        "doiUrl": "https://doi.org/10.63721/25jbasr0105",
        "title": "CRISPR-Mediated Gene Editing: A Revolutionary Strategy for Treatment of Cutaneous Diseases",
        "subtitle": null,
        "type": "journal-article",
        "containerTitle": "Journal of Biomedical Advancement Scientific Research",
        "issn": ["3069-0854"],
        "publisher": "Way Makers LLC",
        "publishedDate": "2025-08-18",
        "publishedPrint": null,
        "publishedOnline": "2025-08-18",
        "registeredAt": "2026-10-13T06:48:48Z",
        "indexedAt": "2026-10-13T07:45:19Z",
        "authors": [
            {
                "name": "Ahmad M Khalil",
                "given": "Ahmad M",
                "family": "Khalil",
                "orcid": null,
                "orcidAuthenticated": null,
                "affiliations": ["Department of Biological Sciences, Yarmouk University, Irbid- Jordan"],
                "rorIds": [],
                "sequence": "first"
            }
        ],
        "authorCount": 1,
        "authorsTruncated": false,
        "firstAuthor": "Ahmad M Khalil",
        "funders": [],
        "licenceUrls": [],
        "openAccessUrl": null,
        "openAccessStatus": null,
        "referenceCount": 433,
        "citedByCount": 0,
        "subjects": [],
        "updates": [],
        "retracted": false,
        "source": "crossref",
        "openAlexId": null,
        "stateStore": "my-lab-watch",
        "checkedAt": "2026-10-13T22:13:30.347Z"
    },
    {
        "status": "ok",
        "watchType": "doi",
        "watchLabel": "Papers we cite",
        "watchValue": "10.1016/s0140-6736(97)11096-0",
        "changeType": "baseline",
        "doi": "10.1016/s0140-6736(97)11096-0",
        "title": "RETRACTED: Ileal-lymphoid-nodular hyperplasia, non-specific colitis, and pervasive developmental disorder in children",
        "type": "journal-article",
        "containerTitle": "The Lancet",
        "publisher": "Elsevier BV",
        "publishedDate": "1998-02",
        "registeredAt": "2002-07-25T12:19:56Z",
        "authorCount": 13,
        "firstAuthor": "AJ Wakefield",
        "citedByCount": 2038,
        "updates": [
            { "type": "correction", "label": "Correction", "noticeDoi": "10.1016/s0140-6736(04)15715-2", "date": "2004-03-06", "source": "retraction-watch" },
            { "type": "retraction", "label": "Retraction", "noticeDoi": "10.1016/s0140-6736(10)60175-4", "date": "2010-02-06", "source": "retraction-watch" }
        ],
        "retracted": true
    },
    {
        "status": "not-found",
        "errorCode": "not-found",
        "error": "Crossref has no record of 10.9999/does-not-exist-xyz. Check the DOI; it may also be registered with another agency, such as DataCite, which this Actor does not read. Later runs will not repeat this row; the run summary counts it. Nothing was charged.",
        "watchType": "doi",
        "watchValue": "10.9999/does-not-exist-xyz",
        "doi": "10.9999/does-not-exist-xyz",
        "title": null
    }
]
```

The rows come from a recorded run on 13 Oct 2026, with the store name of the example input. The second and third are shortened here. Every row carries every field, with `null` where a value does not apply, so exports keep the same columns.

A doi watch row for a DOI that gained a correction carries the same fields, plus what changed:

```json
{
    "status": "ok",
    "watchType": "doi",
    "doi": "10.1155/2022/9175402",
    "title": "A Pan-Cancer Analysis on the Systematic Correlation of MutS Homolog 2 (MSH2) to a Malignant Tumor",
    "containerTitle": "Journal of Oncology",
    "changeType": "changed",
    "changes": [{ "field": "updates", "old": null, "new": "correction 10.1155/jo/9756191 (2026-09-30)" }],
    "updates": [{ "type": "correction", "label": "Correction", "noticeDoi": "10.1155/jo/9756191", "date": "2026-09-30", "source": "publisher" }],
    "retracted": false
}
```

A cited-by change reads `{ "field": "citedByCount", "old": 2031, "new": 2038 }`.

### Tips for faster runs and lower costs

- Save the input as a task, or set `stateStoreName`, before you add or remove watches. Outside a task and without a name, any change to the list starts a new memory, and the next run delivers and charges every watch's baseline again.
- Keep the first-run baseline small with `maxPerWatch` and `since`. A baseline of 10 newest works per watch tells you whether a watch is tuned right for a tenth of the cost of 100.
- Make keyword watches specific. Every word must appear, so `"base editing" CRISPR` finds fewer stray works than three loose words, and `titleOnly` finds fewer still.
- Schedule weekly. Crossref registers new works every day, and a weekly run reports each of them within seven days. A daily run sends the same requests seven times as often for the same works.
- Add `contactEmail`. Crossref asks for one, and its polite pool is meant for requests that carry it.
- A run sends about one request a second. Measured runs of 20 watches took 71 to 78 seconds for a baseline and 27 to 50 seconds for a later run, so 50 watches take about 3 minutes. A run timeout of 10 minutes leaves room for waits after a 429. A run that reaches its limit lists the watches it did not finish in one free `skipped` row, and the next run checks them.

### FAQ, disclaimers and support

#### Where does the data come from, and may I use it?

From Crossref's public REST API, and from OpenAlex's API when you give your key. Crossref metadata is deposited by publishers and is openly available for reuse, and OpenAlex releases its data under CC0. Abstracts can be under the publisher's copyright, which is one reason the Actor never outputs them. How you may use what you collect depends on your purpose and your country, so check that for your use case. This is general information, not legal advice.

#### Is this an official Crossref or OpenAlex tool?

No. The Actor is an independent tool, not affiliated with, made, endorsed or checked by Crossref or OpenAlex. The data comes as Crossref holds it on the day of the run: a publisher can deposit a work days after it appears online, and can change a record later. Open the work's DOI link (the `doiUrl` column) before you act on a row.

#### What counts as new, and where can it be wrong?

After a watch's first run, a work is new to it when its DOI was registered with Crossref after that first run began, and the memory has not delivered it under any watch. Nothing registered before the first run is delivered later, even a work its cut at `maxPerWatch` held back. Each later run reads from its last check minus 7 days, never earlier than the first run, so a work registered shortly before a check but shown by Crossref only after it still arrives. Registration time is used because Crossref re-indexes about a million records a day, so the last-indexed date says little about what is new. Where the result can be wrong:

- **Old works deposited late.** A publisher that deposits an archive of old papers makes them new by this rule. Use `since` to keep a watch to recent publication dates.
- **Works that show up late.** The 7-day look-back catches works Crossref makes searchable some time after their registration time. A work that shows up more than 7 days late, or one registered before the watch's first run, is missed.
- **Keyword watches read by relevance.** When a keyword run reads by relevance and stops before the end of the results (see the next answer), it may not have reached every match, so its own start becomes the floor and the look-back is skipped next time. A match it did not reach is then never delivered, rather than delivered days late as new.
- **The cut at `maxPerWatch`.** When a later run finds more than `maxPerWatch` new works, the older ones are left out for good, and a free `max-per-watch` row says how many.
- **The first run.** A keyword watch's baseline covers the last 30 days. An author, journal or funder baseline is the newest works by registration date, which for an author can include an old paper whose DOI was registered recently.
- **Affiliation watches.** OpenAlex cannot be asked for its newest additions on a free key, so an affiliation watch goes by publication date: a work is new when its publication date is no more than 30 days before the watch's last check (and not before your `since` date), and the watch has not delivered it. A work OpenAlex adds later with an older publication date is missed, and after a cut at `maxPerWatch` nothing published on or before the oldest day delivered comes later.
- **One work, several watches.** A work is delivered under the first watch that finds it. Other watches count it as delivered before and do not repeat it.

#### How does a keyword watch decide what matches, and where can it be wrong?

Crossref's search returns works that hold any of the words, ranked by relevance. The Actor keeps a work only when every word of your query (stop words such as "the" and "of" left out) appears in its title, subtitle or abstract, a "quoted phrase" appears with its words in a row, and a `word*` prefix starts some word. With `titleOnly` the abstract is not even requested. Where the result can be wrong:

- **Words far apart.** The words can sit anywhere in the abstract, so a work about something else can pass. A quoted phrase or `titleOnly` is stricter.
- **Sparse topics.** When fewer than half the works on the first page hold every word, the Actor reads up to 5 pages of 100 by relevance. A match ranked below them is missed.
- **Works without an abstract.** Many records carry no abstract, so such a work matches only on its title and subtitle.
- **Spelling.** Accents and punctuation are removed, but there is no stemming: `edit` does not match `editing`. Use `edit*`.

#### How are retractions and corrections found, and where can they be wrong?

From the update notices on each work's Crossref record, which carry the notice DOI, its type and date, and its source: the publisher, or the Retraction Watch data Crossref holds. A doi watch remembers each DOI's notices and cited-by count and delivers the DOI again when either moved. A notice that disappears is reported too, with `new` empty. Where the result can be wrong:

- **Notices nobody deposited.** A retraction that the publisher never deposited, and that is not in the Retraction Watch data, does not show.
- **Cited-by counts.** `citedByCount` counts only citations from works Crossref holds, so it is lower than some other indexes, and it can fall when a citing record is corrected.
- **DOIs from other agencies.** A DOI registered with another agency than Crossref is reported once as `not-found`.

#### Is personal data involved?

Authors are people. The Actor keeps author names, ORCID iDs and affiliations as the record shows them, because they identify who wrote a work. It drops every email address it reads and never outputs abstracts. Under the GDPR and similar laws you are the controller of what you collect, so keep and use it for a lawful reason.

If a row is about you and you want it out of this Actor's output, open an issue on the **Issues** tab with the DOI or your ORCID iD. A work removed this way is left out of all future output: a doi watch returns a free `removed` row in its place. An author removed this way appears as "Removed on request", without the ORCID iD or affiliations. The record stays at Crossref and OpenAlex, which only the publisher and those services can change.

#### How does the Actor remember what it delivered, and how do I start over?

After each run it keeps, per watch, the DOIs it delivered (the newest 5,000), the watch's floor and the time of its last check, and for doi watches each DOI's notices and cited-by count, in a named key-value store listed in each row as `stateStore`. No key and no email address is stored. To start over, delete that store under **Storage** in Console, or set a new `stateStoreName`. A failed or skipped watch keeps its last good check, so the next run catches up.

#### What happens when Crossref limits the requests?

Every Crossref answer announces its rate limit (1 request a second, one at a time, on 14 Oct 2026). The Actor follows the announced rate and keeps a little under it. A "too many requests" answer (HTTP 429) is waited out for as long as its Retry-After header says, or 60 seconds, and three in a row stop the run. Watches it did not finish get one free `skipped` row with the code `rate-limited`, and the next run checks them. A server error is retried three times with growing waits.

#### What happens with my OpenAlex key?

`openAlexApiKey` is a secret input, encrypted by Apify. The Actor sends it only to OpenAlex and never writes it to a row, the summary, the memory or the log. It stops asking OpenAlex at `openAlexMaxRequests`, when OpenAlex's cost headers say the key's daily allowance is too low for another request, at the first refusal of the key, or after three 429 answers. Affiliation watches then get a free `skipped` row, and the Crossref watches carry on. A list request cost $0.0001 of the allowance on 14 Oct 2026, so the default cap of 50 requests uses $0.005 of it.

#### What happens when a run reaches its time limit?

The Actor reads the time limit of the run from the platform and starts no new watch in the last 30 seconds. What it did not finish gets one free `skipped` row with the code `run-time-limit`, and the next run checks those watches.

#### What if something looks wrong?

Open the Issues tab on the Actor page and describe your input and what you expected. A run link helps. Issues are answered within two days.

### Other Actors by the same developer

- [SEC EDGAR Filing Monitor](https://apify.com/lone_rachis/sec-edgar-filing-monitor): new SEC filings for the tickers or CIKs you watch.
- [SEC Form D Feed](https://apify.com/lone_rachis/sec-form-d-raises-feed): new private fundraising rounds filed with the SEC on Form D, with amounts and industry.
- [SEC XBRL Fundamentals](https://apify.com/lone_rachis/sec-xbrl-fundamentals): revenue, EPS, cash flow and other reported figures per company and period, from SEC XBRL filings.
- [UK Company Check](https://apify.com/lone_rachis/uk-company-check): Companies House status, outstanding charges and risk flags for UK companies, or a list of newly registered ones.
- [US Trademark Status and Watch](https://apify.com/lone_rachis/us-trademark-status-watch): USPTO status and upcoming deadlines for US trademarks, and what changed since your last run for marks you watch.
- [Full Page Website Screenshot](https://apify.com/lone_rachis/full-page-website-screenshot): full-page PNG or JPEG screenshots, including pages that load content as you scroll.

# Actor input Schema

## `watches` (type: `array`):

Up to 50 watches, each an object with a type. {"type": "query", "keywords": "CRISPR base editing"} finds works holding every word (add "titleOnly": true to search titles only). {"type": "author", "orcid": "0000-0002-1825-0097"}, {"type": "journal", "issn": "1476-4687"}, {"type": "funder", "funderId": "10.13039/100000001"} and {"type": "affiliation", "ror": "03vek6s52"} (OpenAlex key needed) find new works. {"type": "doi", "dois": \["10.1038/nature12373"]} reports retractions, corrections and cited-by changes. Every type but doi takes "since": "2026-01-01" (published on or after) and every type a "label". The first run delivers the newest works as a baseline; later runs only what is new.

## `maxPerWatch` (type: `integer`):

The most works one watch delivers in one run, newest first. The first run of a watch is its baseline: its newest works up to this number. When a later run finds more new works than this, the newest are delivered, the older ones are left out for good, and a free row says how many.

## `contactEmail` (type: `string`):

Optional. Crossref asks API users for a contact address and sends requests that carry one to its faster polite pool. The Actor puts it in the User-Agent header of requests to Crossref only. It is never logged, stored in the output or memory, or sent anywhere else.

## `stateStoreName` (type: `string`):

Optional. The name of the key-value store that remembers what each watch delivered. With a name, such as my-lab-watch, an added watch delivers only its own baseline. Left empty, a run of a saved task keeps one memory per task, which works the same way; a run outside a task names the memory after its watches, so adding or changing a watch there starts a new memory and the next run delivers every watch's baseline again. Letters, digits and dashes.

## `openAlexApiKey` (type: `string`):

Optional. With your own key from a free OpenAlex account, affiliation (ROR) watches work, and rows get an open-access link and the authors' ROR IDs. OpenAlex counts every request against your key's daily allowance, so the Actor caps its calls (below) and stops when the allowance runs low. Without a key the Actor never calls OpenAlex. Stored encrypted; never written to the output or the log.

## `openAlexMaxRequests` (type: `integer`):

The most requests one run sends to OpenAlex with your key. A list request cost $0.0001 of OpenAlex's allowance on 14 Oct 2026, so 50 requests cost about $0.005. 0 turns OpenAlex off.

## Actor input object example

```json
{
  "watches": [
    {
      "type": "query",
      "keywords": "large language models",
      "label": "LLM papers"
    },
    {
      "type": "query",
      "keywords": "CRISPR base editing",
      "label": "Base editing"
    },
    {
      "type": "author",
      "orcid": "0000-0001-9161-999X",
      "label": "Jennifer Doudna"
    }
  ],
  "maxPerWatch": 10,
  "openAlexMaxRequests": 50
}
```

# Actor output Schema

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

Dataset with one row per delivered work: DOI, title, type, journal and ISSN, publisher, publication, registration and index dates, authors with ORCID iDs and affiliations, funders, licence links, the open-access link when you give an OpenAlex key, reference and cited-by counts, subjects, update notices such as retractions and corrections, the watch that matched, and for doi watches the list of changes.

## `summary` (type: `string`):

Counts of watches checked, works delivered as a baseline or as new, DOI rows, works found again but delivered before, held back by maxPerWatch, not found, invalid, failed and skipped, the charged rows, the stop reason, whether OpenAlex was used and what it cost, the requests sent to Crossref and the rate limit it gave, each watch's own counts, and the run time.

# 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 = {
    "watches": [
        {
            "type": "query",
            "keywords": "large language models",
            "label": "LLM papers"
        },
        {
            "type": "query",
            "keywords": "CRISPR base editing",
            "label": "Base editing"
        },
        {
            "type": "author",
            "orcid": "0000-0001-9161-999X",
            "label": "Jennifer Doudna"
        }
    ],
    "maxPerWatch": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("lone_rachis/scholarly-papers-watch").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 = {
    "watches": [
        {
            "type": "query",
            "keywords": "large language models",
            "label": "LLM papers",
        },
        {
            "type": "query",
            "keywords": "CRISPR base editing",
            "label": "Base editing",
        },
        {
            "type": "author",
            "orcid": "0000-0001-9161-999X",
            "label": "Jennifer Doudna",
        },
    ],
    "maxPerWatch": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("lone_rachis/scholarly-papers-watch").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 '{
  "watches": [
    {
      "type": "query",
      "keywords": "large language models",
      "label": "LLM papers"
    },
    {
      "type": "query",
      "keywords": "CRISPR base editing",
      "label": "Base editing"
    },
    {
      "type": "author",
      "orcid": "0000-0001-9161-999X",
      "label": "Jennifer Doudna"
    }
  ],
  "maxPerWatch": 10
}' |
apify call lone_rachis/scholarly-papers-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lone_rachis/scholarly-papers-watch"
        }
    }
}
```

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/FfLX9hDgEJB2GHifc/builds/3cC3c7ub1NmDYsbMh/openapi.json
