# OpenAlex Scraper (`dami_studio/openalex-scraper`) Actor

OpenAlex scraper: search papers by keyword and get the abstract back as readable text. Each row holds the title, authors, institutions, year, venue, citation count, topic tags, DOI and the open-access link when a free copy is known. Raw OpenAlex filters work too. $2.00 per 1,000 works.

- **URL**: https://apify.com/dami_studio/openalex-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Developer tools, AI, Other
- **Features:** Limited permissions
- **Stats:** 6 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.94 / 1,000 works

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

**Search OpenAlex by keyword and get one row per paper with the abstract as readable text**: the
title, the authors and their institutions, the year, the citation count, the DOI, whether it is open
access and where to read it for free.

The abstract is the part that takes work. OpenAlex does not store abstracts as text. It stores a
word-position index, and this actor rebuilds the sentences from it. A paper with no index has no
abstract, and the field is `null` rather than a guess.

| | |
|---|---|
| **Input** | Search keywords, with an optional OpenAlex filter |
| **Output** | One row per work: title, abstract, authors, institutions, year and date, type, venue, citations, topics, DOI, open-access link |
| **Ceiling** | 50 works per run without an OpenAlex API key, since OpenAlex serves only a search's first 50 works to callers without one: a bigger ask gets those 50 and a free note saying so. With your own free key, up to 10,000 |
| **Account needed** | None. Your own OpenAlex API key is optional, for more than 50 works |
| **Price** | $2.00 per 1,000 works on the Free plan, a little less on paid plans. The free plan's $5 a month covers about 2,500 |

### 🔍 What OpenAlex Scraper does

Your keywords go against OpenAlex's own search, which reads titles, abstracts and full text where it
has them. The run returns the first 50 matches in the order you pick, or fewer if you ask for fewer.
Give it your own OpenAlex API key and it keeps going, up to 10,000.

You can order by relevance, by citation count or by date, and set a published-on-or-after floor. For
anything more specific there is a raw filter field that goes straight through to OpenAlex, so
`type:article,is_oa:true` works exactly as their documentation describes it.

Nothing is written to your dataset until the whole set has been collected, so you get either the
full result set or a diagnostic row explaining why not.

### 📋 What data you get from each OpenAlex paper

| What you get | Field |
|---|---|
| OpenAlex's permanent id, and the DOI when there is one | `openalexId`, `doi` |
| Title and the abstract as plain text | `title`, `abstract` |
| Authors, and the institutions they were affiliated with | `authors`, `institutions` |
| Year and full publication date | `year`, `publicationDate` |
| What kind of work it is, and where it appeared | `type`, `venue` |
| How many works cite it | `citations` |
| OpenAlex's topic tags | `concepts` |
| Whether a free copy is known, and where | `isOpenAccess`, `oaUrl` |
| A link to the work on OpenAlex | `url` |

### ▶️ How to scrape OpenAlex papers

1. Open [OpenAlex Scraper](https://apify.com/dami_studio/openalex-scraper) and click **Try for free**.
2. Type your keywords into **Search query**.
3. Set **Max works**. Start around 50 to see the row shape.
4. Pick a **Sort by**, add a **From publication date** if you want, then click **Start**.
5. Download the dataset as JSON, CSV or Excel, or read it from the Apify API.

### 💰 How much does it cost to scrape OpenAlex?

**$2.00 per 1,000 works** on the Free plan. Paid plans pay a little less: $1.98 on Starter, $1.96 on Scale and $1.94 on Business. On the free plan, the $5 Apify
gives you each month covers about 2,500 works.

You pay per work delivered. Works that appear twice across pages are dropped before they are counted,
diagnostic rows are not charged, and a search that matches nothing is not charged. Set a maximum cost
on the run and it stops when it gets there.

### 📥 What you give it

```json
{
  "query": "protein folding",
  "sort": "citations",
  "fromDate": "2020-01-01",
  "maxItems": 50
}
```

| Field | Default | What it is |
|---|---|---|
| `query` | none, the form starts with `machine learning` | The keywords to search for. Required. |
| `fromDate` | none | `YYYY-MM-DD`. Only works published on or after this date. |
| `sort` | `relevance` | `relevance`, `citations` for most cited, or `date` for newest first. |
| `filter` | none | An OpenAlex filter string, passed through untouched. Comma-separated `key:value` pairs such as `type:article,is_oa:true`. |
| `maxItems` | `100` | How many works to return, up to 10,000. Without an `apiKey` a run returns 50 at most. |
| `apiKey` | none | Optional. Your own free OpenAlex API key, kept secret. It lifts the 50-work limit. |
| `notionConnector` | none | Optional. Writes each work into your Notion once the run finishes. |
| `notionParentId` | none | Optional. The Notion data source to write into. |
| `proxyConfiguration` | off | Optional network settings. Off by default, and a normal run does not need it. |

**`filter` is handed to OpenAlex as you typed it.** A key or value OpenAlex cannot read comes back
as a free `BAD_INPUT` row with OpenAlex's own explanation in `details`, so a typo does not pass for a
search that matched nothing.

**If your `filter` already contains `from_publication_date`, the `fromDate` field is ignored.** Set
the date in one place, not both.

### 📤 What you get back

A real row from a run on 2 October 2026, with the lists and the abstract cut short (the row carries
19 authors and 10 institutions):

```json
{
  "ok": true,
  "openalexId": "https://openalex.org/W2101234009",
  "doi": "https://doi.org/10.48550/arxiv.1201.0490",
  "title": "Scikit-learn: Machine Learning in Python",
  "authors": ["Fabián Pedregosa", "Gaël Varoquaux", "Alexandre Gramfort", "Michel, Vincent", "..."],
  "institutions": ["Commissariat à l'Énergie Atomique et aux Énergies Alternatives", "..."],
  "year": 2012,
  "publicationDate": "2012-01-02",
  "type": "article",
  "venue": "ORBi (University of Liège)",
  "citations": 63573,
  "concepts": ["Python (programming language)", "Documentation", "Computer science", "MIT License", "Artificial intelligence"],
  "isOpenAccess": true,
  "oaUrl": "https://orbi.uliege.be/handle/2268/225787",
  "abstract": "Scikit-learn is a Python module integrating a wide range of ... machine learning algorithms for medium-scale supervised and unsupervised problems. ...",
  "url": "https://openalex.org/W2101234009"
}
```

| Field | How to read it |
|---|---|
| `openalexId` | OpenAlex's permanent id. Use it as your key, since not every work has a DOI. |
| `abstract` | Rebuilt from OpenAlex's word-position index. `null` where there is no index to rebuild from. |
| `authors` | Names as OpenAlex holds them, so a few arrive family name first, like `Michel, Vincent`. |
| `venue` | OpenAlex's primary location for the work. Often the journal, but it can be a repository, as above, or `null`. |
| `citations` | OpenAlex's cited-by count, and `0` when OpenAlex has no figure at all. |
| `institutions` | The affiliations OpenAlex resolved for the authors, without repeats. Sometimes messy, because the matching is theirs. |
| `concepts` | Up to five of OpenAlex's own topic tags, not keywords the authors chose. |
| `isOpenAccess`, `oaUrl` | Whether a free copy is known, and where it is. `oaUrl` is `null` when none is known. |
| `type` | `article`, `preprint`, `book-chapter`, `dataset` and so on, in OpenAlex's vocabulary. |

### 🧾 Reading the output

Two kinds of row land in your dataset, and `ok` tells them apart.

| Row | How to spot it | Billed |
|---|---|---|
| A work | `ok: true` and an `openalexId` | yes |
| A diagnostic | `ok: false` and an `errorCode` | no |

The overview table in the Apify Console shows the work columns only, so a diagnostic row looks blank
there. Switch to the JSON or All fields view to read it.

| Code | What it means |
|---|---|
| `BAD_INPUT` | No query was given, OpenAlex could not read the filter or the from-date, or it did not accept your API key. `details` has OpenAlex's reason. |
| `NO_RESULTS` | The request worked and nothing came back. |
| `RATE_LIMITED` | OpenAlex asked for a slower pace than the run could keep. Try a smaller run. |
| `SERVER_ERROR` | OpenAlex answered with a server error. Usually passes. |
| `NOT_SERVED` | This request was not served this run. Re-run it later. Runs before 13 October 2026 wrote `BLOCKED` here, and runs from 13 to 17 October wrote `NETWORK`. |
| `NETWORK` | OpenAlex was unreachable. Re-run it. |
| `TIME_LIMIT` | The run got close to its time limit and stopped on its own. The works delivered before that are complete and charged. Give the run more time, or ask for fewer works, to get the rest. |
| `PARTIAL` | OpenAlex stopped serving the search before the run had what you asked for. The works before this row are complete and charged. `worksDelivered` says how many came back and `count` how many match. |

A run that ends on one of these rows still finishes as succeeded, including when the time limit
stopped it before any work came back: the `TIME_LIMIT` row and an amber status message say so.

### 💡 What people use it for

- Pulling a field's most-cited work with the abstracts attached, in one file, for a reading list.
- Feeding titles and abstracts to a model that has to summarise research it was not trained on.
- Finding which institutions keep appearing on a topic, using the `institutions` field.
- Filtering to open access with `is_oa:true`, so every row has somewhere to read it for free.
- Watching a topic on a schedule with `sort` on `date`, so each run surfaces what is new.

### 🚧 What it does not do

- **Keyword search over works only.** No author, institution or funder lookup by entity.
- **No full text.** You get the abstract and a link, not the paper.
- **Abstracts are missing where OpenAlex has no index for them**, and that is common on older and
  paywalled records.
- **`citations` cannot tell you zero from unknown.** Both read `0`.
- **No more than 50 works per search without a key.** Ask for 500 and you get the first 50 in your
  sort order, plus a free `PARTIAL` row. Your own OpenAlex API key lifts that.
- **No end date field.** Use the raw filter if you need an upper bound.
- **Institutions and concepts are OpenAlex's matching**, and it is not perfect. Treat them as hints,
  not as ground truth.
- **All or nothing.** A failure partway through discards what had been collected, so you get a
  diagnostic row rather than a partial set.
- It is not an official OpenAlex tool. Dami's Studio is independent and is not affiliated with or endorsed by OpenAlex, or by any other company named on this page.

### 🧭 Which research scraper do you need?

| If you want | Use |
|---|---|
| arXiv preprints with full abstracts and PDF links | [arXiv Scraper](https://apify.com/dami_studio/arxiv-scraper) |
| Works with a registered DOI, with its journal, publisher and ISSN | [Crossref Scraper](https://apify.com/dami_studio/crossref-scraper) |
| Papers with readable abstracts, institutions and open-access links | This one |
| Patents rather than papers | [Google Patents Search Scraper](https://apify.com/dami_studio/google-patents-search-scraper) |
| Book records by keyword, title or ISBN | [Books Scraper](https://apify.com/dami_studio/books-scraper) |
| Encyclopedia articles as plain text | [Wikipedia Scraper](https://apify.com/dami_studio/wikipedia-scraper) |
| arXiv, OpenAlex and Wikipedia searches as tools for an AI agent | [Research MCP Server](https://apify.com/dami_studio/research-mcp-server) |

### ❓ Questions people ask

#### Do I need an OpenAlex account or an API key?

Not for the first 50 works of a search. For more, get a free key from your account settings on
openalex.org and paste it into **OpenAlex API key**. It goes only to OpenAlex, stays out of your
dataset and log, and the price per work is the same.

#### Why is the abstract null on some papers?

OpenAlex only keeps a word-position index for a work if the publisher made one available. No index,
no abstract to rebuild.

#### Why is the venue a repository instead of a journal?

OpenAlex picks one primary location per work, and for a paper with a preprint or a repository copy
it sometimes picks that. The DOI still points at the published version.

#### Can I search by author or institution?

Not as a mode. You can approximate it through the raw `filter` field, using OpenAlex's own filter
keys.

#### Can I call it from code or connect it to an AI assistant?

The [API tab](https://apify.com/dami_studio/openalex-scraper/api/python) has code for Python, JavaScript and the CLI.
MCP clients like Claude and ChatGPT use
`https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/openalex-scraper`; coding assistants can load [our skill
file](https://api.apify.com/v2/key-value-stores/BTBHU3DdiuoF4JOsK/records/apify-open-data-research-SKILL.md). All
three bill your Apify account at the same price.

#### Is scraping OpenAlex legal?

Apify's write-up on [the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/) is
a good starting point, and we are not lawyers.

### 🆘 If something breaks

Open the **Issues** tab on the actor page. Send the run ID, the query and any `filter` you used. The
`errorCode` on the diagnostic row usually names the problem on its own.

# Actor input Schema

## `query` (type: `string`):

Keywords to search OpenAlex works for (title, abstract and fulltext are searched), e.g. "machine learning", "crispr gene editing". Required.

## `fromDate` (type: `string`):

Optional. Only return works published on or after this date (YYYY-MM-DD, e.g. 2023-01-01). Adds a from_publication_date filter.

## `sort` (type: `string`):

How to order results: Relevance (best match for the query), Citations (most-cited first), or Date (newest first).

## `filter` (type: `string`):

Optional advanced filter passed straight to the OpenAlex API filter param. Comma-separated key:value pairs, e.g. "type:article,is_oa:true,from_publication_date:2023-01-01". See the OpenAlex docs for available filter keys. Merged with From publication date.

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

Maximum number of works to return. Without an OpenAlex API key a run returns 50 at most, because OpenAlex serves only the first 50 works of a search to callers without one. A free key from OpenAlex, pasted into the OpenAlex API key field below, lifts that limit, up to 10,000.

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

Optional. Your own free OpenAlex API key, from your account settings on openalex.org. Leave it empty and a run returns up to 50 works. With it, the run keeps going until it has Max works or the search runs out. It is sent only to OpenAlex and is not written to the dataset or the log, and the searches count against your key's own daily OpenAlex allowance. The price per work is the same either way.

## `notionConnector` (type: `string`):

Optional. Write each result as a page into your Notion when the run finishes. Authorize a Notion connector once in Settings → API & Integrations → MCP connectors, then pick it here. Leave empty to skip (default), results are always saved to the dataset regardless.

## `notionParentId` (type: `string`):

Optional. The Notion data source ID of the database to write into (only used if a Notion connector is set). Leave empty to create the pages privately in your workspace instead.

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

OPTIONAL. Not needed for a normal run.

## Actor input object example

```json
{
  "query": "machine learning",
  "sort": "relevance",
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Scraped rows are stored in the default dataset (one row per result). Empty or failed runs return a single uncharged diagnostic row instead.

# 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 = {
    "query": "machine learning"
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/openalex-scraper").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 = { "query": "machine learning" }

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/openalex-scraper").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 '{
  "query": "machine learning"
}' |
apify call dami_studio/openalex-scraper --silent --output-dataset

```

## MCP server setup

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

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/7f5cgf0WZ8jGq2rju/builds/8EKg5lQqtyy8yLrBN/openapi.json
