# OpenAlex Scholarly Papers & Authors (`grit-77/openalex-papers`) Actor

OpenAlex scholarly metadata scraper for research datasets. Export work, author or institution records as JSON with source metadata and available citation fields.

- **URL**: https://apify.com/grit-77/openalex-papers.md
- **Developed by:** [Grit](https://apify.com/grit-77) (community)
- **Categories:** AI, Education
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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?

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

## OpenAlex Scholarly Papers & Authors

OpenAlex papers scraper returns scholarly work, author, or institution records with source metadata and available citation fields.

OpenAlex papers scraper uses the public source named below and writes its results to the Actor dataset.

Use it for literature discovery, author and affiliation lookup, citation analysis and research input for AI agents. It reads the official [OpenAlex API](https://help.openalex.org/api/llm-quick-reference/). [OpenAlex metadata is released under CC0](https://help.openalex.org/data/how-its-built/).

### What it returns

Fields vary by result type and optional enrichment. The examples below are from `sample_output.json`.

| Output field | Type | Example value or excerpt from saved sample |
|---|---|---|
| `entity_type` | string | `"work"` |
| `status` | string | `"ok"` |
| `query` | string | `"transformer neural network"` |
| `openalex_id` | string | `"https://openalex.org/W4385245566"` |
| `name` | string | `"Exploiting Generative AI to Scale up Intelligent Tutoring Systems"` |
| `api_url` | string | `"https://api.openalex.org/works/W4385245566"` |
| `cited_by_count` | integer | `78458` |
| `errors` | array | `[]` |
| `retrieved_at` | string | `"2026-10-05T11:33:57.222687+00:00"` |
| `source_updated_at` | string | `"2026-10-03T13:16:28.481748"` |
| `title` | string | `"Exploiting Generative AI to Scale up Intelligent Tutoring Systems"` |
| `doi` | string | `"https://doi.org/10.4230/lipics.itp.2023.19"` |
| `publication_year` | integer | `2023` |
| `publication_date` | string | `"2023-01-01"` |
| `work_type` | string | `"article"` |
| `language` | string | `"en"` |
| `abstract` | string or null | `"As a present to Mizar on its 50th anniversary, we develop an AI/TP system that automatically proves…` |
| `authors` | array | `[{"openalex_id": null}]` |
| `institutions` | array | `[{"openalex_id": "https://openalex.org/I44504214"}]` |
| `is_open_access` | boolean | `true` |
| `oa_status` | string | `"green"` |
| `oa_url` | string | `"https://drops.dagstuhl.de/storage/00lipics/lipics-vol268-itp2023/LIPIcs.ITP.2023.19/LIPIcs.ITP.2023.19.pdf"` |
| `landing_page_url` | string | `"https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.ITP.2023.19"` |
| `pdf_url` | string or null | `"https://drops.dagstuhl.de/storage/00lipics/lipics-vol268-itp2023/LIPIcs.ITP.2023.19/LIPIcs.ITP.2023.19.pdf"` |
| `source_name` | string | `"DROPS (Schloss Dagstuhl – Leibniz Center for Informatics)"` |
| `source_id` | string | `"https://openalex.org/S4377196569"` |
| `referenced_works` | array | `[]` |
| `concepts` | array | `[{"id": "https://openalex.org/C41008148"}]` |
| `topics` | array | `[{"id": "https://openalex.org/T10181"}]` |

Choose `works`, `authors` or `institutions` for each run. Results from multiple queries are deduplicated by OpenAlex ID. Dataset views separate the overview, works, authors, institutions and provenance fields.

| Fields | Meaning |
|---|---|
| `entity_type`, `status`, `query` | Record kind, `ok`/`error` and the query that first produced the row |
| `openalex_id`, `api_url`, `name` | Stable OpenAlex ID, official record URL and display name |
| `cited_by_count` | OpenAlex citation count for the selected entity |
| `title`, `doi`, `publication_year`, `publication_date` | Work bibliography |
| `work_type`, `language`, `source_name`, `source_id` | Work type, language and primary source |
| `abstract` | Available inverted-index abstract reconstructed in token order; otherwise null |
| `authors` | Work authors with IDs, ORCIDs, positions and institutional affiliations |
| `institutions` | Work affiliations or an author's last known institutions from OpenAlex |
| `is_open_access`, `oa_status`, `oa_url` | Open-access metadata and an available access link |
| `landing_page_url`, `pdf_url` | Public record/PDF links when supplied by OpenAlex |
| `referenced_works`, `concepts`, `topics` | Referenced work IDs and subject classifications |
| `works_count`, `h_index`, `i10_index`, `two_year_mean_citedness` | Author/institution bibliometric indicators when supplied |
| `orcid`, `works_api_url`, `counts_by_year` | Author identity link, related works query and available annual counts |
| `ror`, `country_code`, `institution_type`, `homepage_url` | Institution identity, country, type and homepage |
| `city`, `region`, `country`, `latitude`, `longitude` | Public institution location |
| `retrieved_at`, `source_updated_at`, `errors` | Retrieval time, source update time and processing errors |

Fields vary by entity type; missing optional source values remain null or empty lists. An error row contains its entity type, query, status and error message. An unavailable or malformed abstract does not discard otherwise usable work metadata.

### Input example: scholarly works

```json
{
  "entityType": "works",
  "queries": ["transformer neural network"],
  "yearFrom": 2020,
  "yearTo": 2024,
  "conceptIds": ["C154945302"],
  "openAccess": true,
  "minCitations": 100,
  "sortBy": "citations",
  "includeAbstracts": true,
  "maxItems": 8,
  "concurrency": 2
}
```

Years and `minCitations` are inclusive. IDs in one filter list use OR; different filters use AND. `openAccess: false` selects closed-access works; omit the property to include both. Work searches can also filter by `topicIds`, `authorIds` and `institutionIds`. Use IDs such as `C154945302`, `A5108093963`, `I40120149` or their full OpenAlex URLs.

[Concepts are deprecated and frozen](https://help.openalex.org/data/concepts/), so use `topicIds` for current classification coverage. Concept filtering is retained for existing workflows.

Author search:

```json
{"entityType":"authors","queries":["Geoffrey Hinton"],"minCitations":100,"maxItems":10}
```

For author affiliation searches, `institutionIds` refers to the author's last known institutions. Institutional affiliation here reflects the source's publication metadata, not verified current employment.

Institution search:

```json
{"entityType":"institutions","queries":["University of Oxford"],"countryCode":"GB","institutionType":"education","maxItems":10}
```

`sortBy` accepts `relevance` (default), `citations`, `year` (works) or `worksCount` (authors/institutions). Incompatible filters fail with a field-specific message.

### Real output example

Selected fields from the checked local dataset; [sample_output.json](sample_output.json) contains the complete rows:

```json
{
  "entity_type": "work",
  "openalex_id": "https://openalex.org/W4385245566",
  "title": "Exploiting Generative AI to Scale up Intelligent Tutoring Systems",
  "publication_year": 2023,
  "cited_by_count": 78458,
  "doi": "https://doi.org/10.4230/lipics.itp.2023.19",
  "is_open_access": true,
  "status": "ok"
}
```

Citation counts and other metadata may change after the sample was captured.

### Pricing proposal

| Custom event | USD per row | USD per 1,000 rows |
|---|---:|---:|
| `work` | 0.0005 | 0.50 |
| `author` | 0.0005 | 0.50 |

Work authors nested in a paper are included in the work price. Institution rows, error rows, duplicates and unmatched searches have no custom event charge. Usable work metadata is billable even when an abstract is unavailable. Apify platform usage and any configured platform start event are separate. The owner must configure the proposed prices before publication; see [PRICING.md](PRICING.md) for dated competitor evidence and setup.

### Limits and reliability

- `queries`: 1–100 non-empty strings, each at most 1,000 characters.
- `maxItems`: 1–100,000, default 100. This is a shared cap on dataset rows, including errors, across the run.
- `concurrency`: 1–10 parallel searches, default 2. Requests share a limiter; pages within each search are sequential.
- Each filter-ID list accepts 1–100 IDs. Publication years accept 1–2100.
- Failed network requests, HTTP 429 and server errors get bounded retries with increasing delays. Permanent API errors become uncharged query error rows; malformed records become uncharged item error rows.
- [Anonymous OpenAlex access has a smaller daily allowance](https://help.openalex.org/api/authentication/). An optional own free key can be supplied as the secret `apiKey` field or the `OPENALEX_API_KEY` environment variable. Keys are sent in an Authorization header and excluded from result/error messages.
- OpenAlex author disambiguation, affiliation inference and citation counts can contain source errors. Abstracts and OA/PDF links are not available for every work.
- A restarted or migrated run can revisit records: deduplication and the global row counter are scoped to one process. Migration/restart recovery has not been implemented or validated.

### FAQ

**What limits a search?** `maxItems` caps rows across queries; results are deduplicated by OpenAlex ID. Source quotas can stop a larger search.

**Do I need a proxy, login, or API key?** Anonymous public access is supported. An optional own OpenAlex API key can increase the source allowance; no proxy is configured.

**How is it priced?** The proposed pay-per-event model charges `work` for a unique work and `author` for a unique author profile. Institution and error rows have no custom event charge.

**How are rate limits handled?** Workers share a request limiter and retry temporary responses with backoff and `Retry-After` when present. A source quota failure is reported.

**How fresh are citation counts?** `retrieved_at` records this fetch and `source_updated_at` reports the source’s update time when available. Citation counts can change.

**Does it download full papers?** No. It returns metadata, available abstracts, and source-provided links.

### Use with AI agents / MCP

After publication, agents can discover and invoke this Actor through the [Apify MCP server](https://docs.apify.com/integrations/mcp) at `https://mcp.apify.com`. Supply the same JSON input and read the default dataset through the Actor's Results output link.

Example agent instruction: “Find open-access transformer research published from 2020 to 2024, with at least 100 OpenAlex citations. Return eight works with titles, DOIs and available abstracts. Preserve each OpenAlex ID and retrieval date.”

For an author-to-paper workflow, first search `authors`, choose the intended returned ID, then search `works` using `authorIds`. For an institution-to-paper workflow, first search `institutions`, then pass its ID as `institutionIds` in a works search.

### Local development

Dependencies: `apify>=4.0,<5`, `httpx>=0.28,<1`. No package was added to the shared virtual environment.

Run from this actor directory with the provided environment, without the Apify CLI. In PowerShell:

```powershell
$env:APIFY_LOCAL_STORAGE_DIR = Join-Path (Get-Location) 'storage'
New-Item -ItemType Directory -Force 'storage/key_value_stores/default' | Out-Null
Copy-Item 'example_input.json' 'storage/key_value_stores/default/INPUT.json'
& 'C:/GritWork/earn/.venv/Scripts/python.exe' -m src
```

Use a fresh storage directory when repeating a run to keep prior datasets separate. The actor also writes a `RUN_SUMMARY` key-value record containing row counts, errors, API requests, custom event count and elapsed time.

Offline tests:

```powershell
& 'C:/GritWork/earn/.venv/Scripts/python.exe' -m pytest -m 'not live' -q
```

Live smoke:

```powershell
& 'C:/GritWork/earn/.venv/Scripts/python.exe' -m pytest -m live -q
```

The real-response fixture URLs and capture time are in `tests/fixtures/SOURCES.json`. Full local and test evidence is in `evidence/`; `scripts/verify_local.py` exercises fresh-storage searches, errors and simulated event budgets. `scripts/compare_sample.py` independently checks saved IDs, bibliography, citation counts and each abstract token position against fresh official API responses. `scripts/validate_package.py` checks the requested metadata paths and package constraints. Docker configuration uses `apify/actor-python:3.12`; a Docker build and cloud run remain for the owner to validate before publication.

# Actor input Schema

## `entityType` (type: `string`):

Search works, author profiles or institutions. One type per run.

## `queries` (type: `array`):

One to 100 non-empty search strings. Results are deduplicated by OpenAlex ID across queries.

## `yearFrom` (type: `integer`):

Works only. Inclusive lower publication year; omit for no lower bound.

## `yearTo` (type: `integer`):

Works only. Inclusive upper publication year; omit for no upper bound.

## `conceptIds` (type: `array`):

Works only. Legacy OpenAlex concept IDs, e.g. C154945302. OR within this list; AND with other filters. Concept names are not accepted.

## `topicIds` (type: `array`):

Works only. OpenAlex topic IDs, e.g. T10028; an alternative to legacy concepts.

## `openAccess` (type: `boolean`):

Works only. True restricts to open-access works, false to closed works; omit to include both.

## `minCitations` (type: `integer`):

Inclusive cited_by_count minimum for the selected entity type.

## `authorIds` (type: `array`):

Works only. Restrict papers to these A-prefixed OpenAlex author IDs.

## `institutionIds` (type: `array`):

Works: affiliation IDs. Authors: last known institution IDs. Accepts I-prefixed IDs or full OpenAlex URLs.

## `countryCode` (type: `string`):

Institutions only. Two-letter country code, e.g. GB.

## `institutionType` (type: `string`):

Institutions only. Restrict to an OpenAlex institution type.

## `sortBy` (type: `string`):

Relevance, citation count descending, publication year descending (works only), or works count descending (authors/institutions only).

## `includeAbstracts` (type: `boolean`):

Works only. Reconstruct available OpenAlex abstract token positions into text.

## `maxItems` (type: `integer`):

Global hard cap across all queries, including error rows. Duplicates do not consume the cap.

## `concurrency` (type: `integer`):

Maximum parallel search workers. All workers share a request limiter and result budget.

## `apiKey` (type: `string`):

Optional own free OpenAlex API key for a larger daily allowance; sent in an Authorization header. Anonymous access is used when omitted.

## Actor input object example

```json
{
  "entityType": "works",
  "queries": [
    "transformer neural network"
  ],
  "sortBy": "relevance",
  "includeAbstracts": true,
  "maxItems": 100,
  "concurrency": 2
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset of work, author or institution records and uncharged error rows.

# 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 = {
    "queries": [
        "transformer neural network"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("grit-77/openalex-papers").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 = { "queries": ["transformer neural network"] }

# Run the Actor and wait for it to finish
run = client.actor("grit-77/openalex-papers").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 '{
  "queries": [
    "transformer neural network"
  ]
}' |
apify call grit-77/openalex-papers --silent --output-dataset

```

## MCP server setup

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

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/qHFbCTlEtkmedv2pA/builds/0z4UzNHn043dPmBpw/openapi.json
