# Research Evidence Radar (`conceivable_extension/research-evidence-radar`) Actor

Tracks a paper's real lifecycle across arXiv, bioRxiv/medRxiv, Crossref, OpenAlex and PubMed — preprint to peer-reviewed to published — and flags retractions urgently. Agent-consumable evidence infrastructure, not a static paper list.

- **URL**: https://apify.com/conceivable\_extension/research-evidence-radar.md
- **Developed by:** [joseph fadero](https://apify.com/conceivable_extension) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 paper returned no changes

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Research Evidence Radar

**"This preprint was published in March, peer-reviewed in June and substantially revised in July"** — the Evidence Evolution example from the source research behind this actor. Existing scraper-style research actors return a static list of papers matching a search term. This actor tracks the same underlying evidence across its real lifecycle — preprint → peer-reviewed → published — merges the same paper across sources instead of double-counting it, and flags retractions urgently.

### Built for AI agents, not just humans reading a list

This is explicitly agent-consumable evidence infrastructure, tying into this account's broader x402/agent-native positioning. An AI research agent asking "what's the current state of evidence on X, and has anything been retracted" gets a structured, entity-resolved, stage-aware answer here — not a page of search results it has to de-duplicate and interpret itself. `isRetraction` and `stageChangedSinceLastRun` are deliberately reliable, structured booleans rather than something an agent has to infer from prose, because — per the PRD's own instruction — a retraction flagged late is a genuine credibility problem for anyone (human or agent) relying on this feed.

### All 6 sources are real; one is real but unreliable without a paid key

| Source | Real access | Role |
|---|---|---|
| `openalex` | Keyless REST API | **Backbone.** Does its own real cross-source entity resolution (confirmed live: "Attention Is All You Need" resolved to 11 real merged locations across arXiv + accepted-version records under one work), a real `is_retracted` boolean (confirmed accurate against the Wakefield MMR-autism retraction), real `cited_by_count`. |
| `arxiv` | Keyless Atom API | Freshest real-time preprint discovery — arXiv's own API can be ahead of OpenAlex's indexing. |
| `crossref` | Keyless REST API | Published-DOI metadata, real citation count (`is-referenced-by-count`). |
| `pubmed` | Keyless E-utilities API | Biomedical coverage; real `pubtype` field can directly say "Retracted Publication." |
| `biorxiv` / `medrxiv` | Keyless REST API | Biomedical preprints — confirmed to be a clean real JSON API despite the PRD's own expectation this would be more scraping-dependent (a positive scope finding). Real bonus: a genuine `published` field cross-referencing the paper's own later published DOI once one exists. |
| `semantic_scholar` | Real API, but keyless/anonymous access shares a global rate-limit pool that was **exhausted on every live test during this build** (repeated HTTP 429, several seconds apart, even after backoff). Handled with one retry then a clean failure record — not treated as a primary source, since OpenAlex already provides a real citation count without this reliability problem. |

### Entity resolution — validated against a real, verified preprint→published pair

The PRD's core differentiator ("don't double-count a preprint and its later published version as two separate records") is handled two ways, confirmed live:

1. **OpenAlex does its own real merging natively** — used as-is for anything queried through OpenAlex.
2. **This actor's own merge (`entityResolver.ts`)** for records fetched directly from other sources: exact-DOI grouping (the same real identity appearing from two sources), plus a source's own real cross-reference to a *different* DOI representing a later stage — bioRxiv/medRxiv's real `published` field is the clearest case.

**Concrete validation**, not a hypothetical: a real bioRxiv preprint (DOI `10.1101/2023.12.31.573522`, "Synaptic connectivity and electrophysiological properties of the nucleus of the lateral olfactory tract") carries a real `published` cross-reference to its own later published version in *The Journal of Neuroscience* (DOI `10.1523/JNEUROSCI.2420-23.2024`, confirmed live via Crossref). Fed both real records through the resolver: **result was one merged record**, `stage: "published"`, `sources: ["biorxiv", "crossref"]`, with the published DOI's own URL as the canonical `sourceUrl` — not two separate papers.

A real bug caught during this validation: the merge initially picked whichever source's record had the fuller abstract as the "canonical" one for *every* field, including `sourceUrl` — which pointed the merged record at the preprint instead of the published version whenever the preprint happened to have richer text. Fixed by tracking "richest record" (for abstract/citations/topics) and "highest-stage record" (for the canonical URL) as two separate things, not one.

### Publication stage — how it's actually derived

- **OpenAlex records:** from real per-location `version`/`is_published` fields (`publishedVersion` or `is_published: true` → published; `acceptedVersion` → peer\_reviewed; else → preprint).
- **Crossref records:** `type: "posted-content"` → preprint; everything else (journal-article, proceedings-article) → published, since Crossref is fundamentally a published-DOI registry.
- **PubMed records:** always `published` — PubMed indexes formally published biomedical literature.
- **arXiv / bioRxiv / medRxiv records:** always `preprint` on their own — upgraded to `published` only via the entity resolver's cross-reference merge described above.

`stageChangedSinceLastRun`/`previousStage` track stage **across runs** (via the same `deltaStore.ts` this program has reused since Actor 26), which is a different mechanism from the entity resolver's **same-run** cross-source merge — validated separately: seeded a known paper's stored stage as `preprint`, re-ran, confirmed the pipeline correctly reported `previousStage: "preprint"`, `publicationStage: "published"`, `stageChangedSinceLastRun: true`.

### Retraction detection — real, tested against a known real case

No single source's retraction signal was trusted blindly — each was checked live:

- **OpenAlex's `is_retracted`:** confirmed accurate against the Wakefield MMR-autism paper (DOI `10.1016/S0140-6736(97)11096-0`) — trusted directly.
- **Crossref's structured `update-to`/`relation` fields:** confirmed **empty in every real retracted record checked**, including the same Wakefield paper (whose title literally starts "RETRACTED:"). The structured field exists in Crossref's schema but isn't populated in practice for retractions — so retraction detection here is title-prefix keyword matching instead, the real reliable signal.
- **PubMed's `pubtype`:** can genuinely include "Retracted Publication" — used directly when present.
- **arXiv:** withdrawn papers conventionally start their abstract "This paper has been withdrawn" — arXiv's own real convention, not a structured field, matched by keyword.

Live end-to-end test: looked up the Wakefield DOI through the full pipeline (not just the raw source) — `isRetraction: true` came through correctly in the actor's own output.

### Modes

| Mode | Behavior |
|---|---|
| `topic_monitor` | Broad keyword search across selected sources |
| `paper_lookup` | Each `topics` entry is treated as a specific identifier (DOI, arXiv ID, or exact title) rather than a keyword — a direct lookup, not a search |

The input schema has one `topics` field shared by both modes, per the original spec — the mode determines how its entries are interpreted, documented here rather than left ambiguous.

### `abstractSummary` — real source text, not a generated summary

Same honesty convention as this program's other actors with a "summary" field: `abstractSummary` is each source's own real abstract text (OpenAlex's is left empty here since it returns an inverted index rather than plain text, and other sources in the same result set already provide real plain-text abstracts in practice) — not an LLM-generated summary. No actor in this program has wired in an external LLM API.

### Output schema

```json
{
  "paperId": "string",
  "title": "string",
  "authors": ["string"],
  "source": "string",
  "publicationStage": "preprint | peer_reviewed | published",
  "previousStage": "string | null",
  "stageChangedSinceLastRun": "boolean",
  "isRetraction": "boolean",
  "citationCount": "number | null",
  "topics": ["string"],
  "abstractSummary": "string",
  "sourceUrl": "string",
  "checkedAt": "ISO timestamp",
  "fetchStatus": "success | failed",
  "errorMessage": "string | null"
}
```

`citationCount` is `null` where a source genuinely doesn't expose one (PubMed's `esummary`, arXiv) rather than guessed — OpenAlex/Crossref/Semantic Scholar provide real counts when available.

### Setup note

No browser needed — all 6 sources work over plain HTTP (JSON/XML/Atom). bioRxiv/medRxiv have no free-text search endpoint, only date-range and DOI-based lookups — `topic_monitor` fetches a recent 21-day window and filters client-side by keyword match, an honest workaround for a real API limitation, not a claim of true server-side search on those two sources specifically.

### Shared "Radar" architecture

- **Diff:** `src/shared/deltaStore.ts` — the same module from Actor 26, reused unmodified across 7 actors now (26, 27, 34, 35, 37, 38, and here), storing each resolved paper's `publicationStage`.
- **Classify/resolve:** real structured signals trusted first (OpenAlex's `is_retracted`, PubMed's `pubtype`), keyword fallback second and labeled as such — the same honesty discipline as every prior Radar actor.

### Pricing

| Event | Price |
|---|---|
| Run started | £0.05 |
| Reading success | £0.06 |
| Fetch failed | free |

### n8n integration

- **Workflow A (trigger):** scheduled weekly run against a watched topic list, logging all new and stage-changed papers to a tracking sheet.
- **Workflow B (processing):** immediate alert on any `isRetraction: true` regardless of topic priority; routine stage advancements logged for a periodic digest.

# Actor input Schema

## `mode` (type: `string`):

topic\_monitor: broad keyword search across selected sources, tracking stage changes/retractions over repeated runs. paper\_lookup: treats each entry in `topics` as a specific paper identifier (a DOI, an arXiv ID like 1706.03762, or an exact title) rather than a keyword — for looking up known papers directly rather than searching. (This actor's input schema has one `topics` field for both modes, per the original spec — the mode determines how its entries are interpreted; see README.)

## `topics` (type: `array`):

topic\_monitor: keyword search terms (e.g. "transformer attention mechanism"). paper\_lookup: specific identifiers (DOI, arXiv ID, or exact title) to look up directly.

## `sources` (type: `array`):

All 6 are real, live sources (see README). semantic\_scholar is real but its keyless/anonymous rate limit is shared globally and frequently exhausted (confirmed live) — included best-effort with retry/backoff, not guaranteed to return results every run. Leave blank for all.

## `watchList` (type: `array`):

Optional, for topic\_monitor mode. A list of { topics, sources } pairs to check on each scheduled run — e.g. weekly, per the n8n companion workflow. If omitted, the top-level topics/sources fields are used directly.

## Actor input object example

```json
{
  "mode": "topic_monitor",
  "topics": [
    "transformer attention mechanism"
  ],
  "sources": [
    "openalex",
    "arxiv"
  ]
}
```

# Actor output Schema

## `resultsDatasetUrl` (type: `string`):

Entity-resolved research evidence tracked across its lifecycle (preprint, peer-reviewed, published, revised, retracted), merged across sources rather than double-counted, produced by this run.

# 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 = {
    "topics": [
        "transformer attention mechanism"
    ],
    "sources": [
        "openalex",
        "arxiv"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("conceivable_extension/research-evidence-radar").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 = {
    "topics": ["transformer attention mechanism"],
    "sources": [
        "openalex",
        "arxiv",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("conceivable_extension/research-evidence-radar").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 '{
  "topics": [
    "transformer attention mechanism"
  ],
  "sources": [
    "openalex",
    "arxiv"
  ]
}' |
apify call conceivable_extension/research-evidence-radar --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,conceivable_extension/research-evidence-radar"
        }
    }
}
```

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/fYaDBTuv8AxYzMqEx/builds/3m37Kac94Xuwnzg6F/openapi.json
