# OpenAlex Scholarly Works Scraper — Search & Filter (`muhammadafzal/openalex-scholarly-works-scraper`) Actor

Search OpenAlex scholarly works by topic, date, type, citations, author, institution, source, and open-access status. Returns one compact, traceable work record per dataset item for literature reviews and bibliometric research. API-backed metadata only; it does not download full text.

- **URL**: https://apify.com/muhammadafzal/openalex-scholarly-works-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Other
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 scholarly work records

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## OpenAlex Scholarly Works Scraper

**OpenAlex Scholarly Works Scraper** searches the OpenAlex catalog and stores one compact, traceable scholarly-work record per dataset item. It supports full-text search, exact search, publication-year ranges, work types, open-access status, citation thresholds, author/institution/source IDs, country filters, advanced OpenAlex filters, sorting, and cursor pagination.

Use it for literature discovery, bibliometric research, citation landscape analysis, open-access screening, research trend datasets, and AI-assisted source discovery. Do not use it to download PDFs, retrieve private full text, or treat citation counts and open-access flags as quality or legal determinations.

The current OpenAlex `/works` API requires an API key. Create a free key at [OpenAlex API settings](https://openalex.org/settings/api) and pass it as the secret `openAlexApiKey` input. The actor uses the documented `/works` API with `per_page` up to 100 and cursor pagination; it stops at `maxResults` and never attempts to download the entire OpenAlex dataset.

### What data can I extract?

Each dataset item represents one OpenAlex work and includes:

| Field | Description |
| --- | --- |
| `openAlexId`, `doi`, `title` | Stable OpenAlex identity, DOI URL, and display title |
| `publicationYear`, `publicationDate`, `workType`, `language` | Bibliographic metadata |
| `citedByCount`, `isRetracted`, `isOpenAccess` | OpenAlex status and citation metadata at extraction time |
| `landingPageUrl`, `pdfUrl` | Best available source links; the actor does not download them |
| `sourceName`, `sourceIssn` | Primary source/journal metadata |
| `authors` | Author IDs, names, ORCIDs, and compact institution names |
| `topics` | OpenAlex topic names |
| `abstract` | Reconstructed abstract when OpenAlex supplies an inverted index |
| `referencedWorksCount`, `relatedWorksCount` | OpenAlex relationship counts |
| `searchQuery`, `appliedFilter`, `scrapedAt` | Run provenance and extraction timestamp |

The detailed format keeps up to 20 authors, 8 topics, and a 4,000-character abstract. The concise format keeps smaller author/topic lists and an 800-character abstract for agent workflows.

### How to use the actor

Start with a narrow search and a small output cap:

```json
{
  "openAlexApiKey": "YOUR_OPENALEX_API_KEY",
  "searchQuery": "machine learning in healthcare",
  "workTypes": ["article", "review"],
  "publicationYearFrom": 2020,
  "publicationYearTo": 2024,
  "openAccessOnly": true,
  "maxResults": 25,
  "responseFormat": "detailed"
}
```

For citation-focused research:

```json
{
  "openAlexApiKey": "YOUR_OPENALEX_API_KEY",
  "searchQuery": "large language models",
  "minCitations": 100,
  "sort": "-citedByCount",
  "maxResults": 100,
  "responseFormat": "concise"
}
```

For an author or institution portfolio, use an OpenAlex ID such as `A5023888391` or `I27837315`. For more advanced filters, use OpenAlex syntax in `advancedFilter`, for example `type:article,has_abstract:true`.

### Input

The main controls are:

| Input | Default | Purpose |
| --- | --- | --- |
| `openAlexApiKey` | required | Current OpenAlex API key; stored as a secret input |
| `searchQuery` | `machine learning` | Full-text search across indexed work text |
| `exactSearch` | `false` | Use unstemmed OpenAlex search |
| `advancedFilter` | empty | Raw documented OpenAlex filter expression |
| `publicationYearFrom`, `publicationYearTo` | empty | Publication-year bounds |
| `workTypes` | `[]` | OR-list of types such as `article`, `dataset`, and `review` |
| `openAccessOnly` | `false` | Keep only works marked open access |
| `minCitations` | empty | Minimum `cited_by_count` |
| `authorId`, `institutionId`, `sourceId` | empty | OpenAlex entity filters |
| `countryCode` | empty | Two-letter institution country code |
| `hasAbstract` | empty | Require or exclude indexed abstracts |
| `sort` | relevance | Relevance, citations, or publication date; prefix `-` for descending |
| `maxResults` | `25` | Maximum output records, 1–1,000 |
| `perPage` | `100` | OpenAlex API page size, 1–100 |
| `responseFormat` | `detailed` | `detailed` or smaller `concise` records |
| `contactEmail` | empty | Optional OpenAlex `mailto` identifier |

### Output example

```json
{
  "openAlexId": "https://openalex.org/W2741809807",
  "doi": "https://doi.org/10.7717/peerj.4375",
  "title": "A scholarly work title",
  "publicationYear": 2024,
  "publicationDate": "2024-01-02",
  "workType": "article",
  "language": "en",
  "citedByCount": 125,
  "isRetracted": false,
  "isOpenAccess": true,
  "landingPageUrl": "https://example.org/article",
  "pdfUrl": "https://example.org/article.pdf",
  "sourceName": "Journal of Example Research",
  "sourceIssn": "1234-5678",
  "authors": [{
    "authorId": "https://openalex.org/A1",
    "displayName": "Ada Lovelace",
    "orcid": null,
    "institutions": ["Analytical Engine Institute"]
  }],
  "topics": ["Machine learning"],
  "abstract": "Reconstructed abstract text when indexed by OpenAlex.",
  "referencedWorksCount": 42,
  "relatedWorksCount": 20,
  "searchQuery": "machine learning",
  "appliedFilter": "type:article,open_access.is_oa:true",
  "scrapedAt": "2026-08-01T12:00:00.000Z"
}
```

### API and integrations

Run the actor through the Apify API, schedule it, export its dataset as JSON/CSV/XLSX, or use it through Apify's hosted MCP integration after deployment. The dataset schema is stable and uses explicit `null` values, so agents can page through the dataset without guessing field names. A run with no matches finishes with a warning and zero records; an invalid key, rate limit, or upstream failure is reported as an actionable error.

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('YOUR_USERNAME/openalex-scholarly-works-scraper').call({
  openAlexApiKey: process.env.OPENALEX_API_KEY,
  searchQuery: 'quantum computing',
  maxResults: 25,
  sort: '-citedByCount'
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("YOUR_USERNAME/openalex-scholarly-works-scraper").call(run_input={
    "openAlexApiKey": os.environ["OPENALEX_API_KEY"],
    "searchQuery": "quantum computing",
    "maxResults": 25,
})
print(client.dataset(run["defaultDatasetId"]).list_items().items)
```

### Data quality and responsible use

OpenAlex metadata can change as records, abstracts, citation links, and open-access locations are updated. Citation counts are not peer-review or research-quality scores. Open-access flags and links are not legal advice, and users must verify licenses and access conditions before redistribution. The actor is independent and is not affiliated with OpenAlex.

### Other dedicated research and data actors

Related workspace projects include [Google Scholar Scraper](../google-scholar-scraper/README.md), [Semantic Scholar Scraper](../semantic-scholar-scraper/README.md), and [AI Citation Monitor](../ai-citation-monitor/README.md). Other data-focused actors in the same portfolio include [FBI Crime Data Scraper](../fbi-crime-data-scraper/README.md), [GSA eLibrary Partner Finder](../gsa-elibrary-partner-finder/README.md), [Harris County Court Records Scraper](../harris-county-court-records-scraper/README.md), [Yellow Pages California Scraper](../yellow-pages-ca-scraper/README.md), and [LandSearch Scraper](../landsearch-scraper/README.md).

### FAQ

#### How many results can I scrape with OpenAlex Scholarly Works Scraper?

Set `maxResults` from 1 to 1,000. The actor uses cursor pagination and stops at that record cap.

#### Can I integrate OpenAlex Scholarly Works Scraper with other apps?

Yes. Use the Apify API, dataset exports, schedules, webhooks, or an Apify integration.

#### Can I use OpenAlex Scholarly Works Scraper with the Apify API?

Yes. Call the actor and read `defaultDatasetId` from the completed run.

#### Can I use OpenAlex Scholarly Works Scraper through an MCP Server?

Yes, after deployment, the stable input and dataset schemas are designed for Apify's hosted MCP exposure.

#### Do I need proxies to query OpenAlex?

No. This actor uses OpenAlex's documented public API, not browser automation or target-site scraping. Use the optional `contactEmail` to identify your requests and keep result caps bounded.

#### Is it legal to use OpenAlex metadata?

Review OpenAlex's current terms, data licensing, source licenses, and applicable law for your use case. This actor does not make legal or licensing determinations.

#### Your feedback

Report an API response change with the run ID, input mode, and a redacted error message so the actor can be repaired without exposing your API key.

# Actor input Schema

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

Your OpenAlex API key used to query the /works endpoint. Get a free key at https://openalex.org/settings/api and paste it here, for example 'oa\_live\_xxx'. This is a secret field and is not included in output records. It is not a DOI or an Apify API token.

## `searchQuery` (type: `string`):

Free-text search across OpenAlex work titles, abstracts, and other indexed text. Enter a topic such as 'machine learning in healthcare'; it defaults to 'machine learning'. Set exactSearch=true for unstemmed matching. This is not a DOI lookup or a raw OpenAlex filter expression.

## `exactSearch` (type: `boolean`):

Use this to search without OpenAlex stemming, for example exactSearch=true with searchQuery='surgery'. It defaults to false for broader discovery. This only changes the search parameter and does not make the title an exact phrase match unless the query itself uses quotes.

## `advancedFilter` (type: `string`):

Optional OpenAlex filter expression appended to structured filters, for example 'type:article,has\_abstract:true'. Use documented OpenAlex field names and comma-separated AND conditions. It defaults to empty. This is not a SQL WHERE clause and must not include api\_key.

## `publicationYearFrom` (type: `integer`):

Return works published in or after this year, for example 2020. Leave empty to disable the lower bound. Combine with publicationYearTo for a closed range. This is a publication-year filter, not a citation date.

## `publicationYearTo` (type: `integer`):

Return works published in or before this year, for example 2024. Leave empty to disable the upper bound. It must be greater than or equal to publicationYearFrom. This is a publication-year filter, not a crawl cutoff.

## `workTypes` (type: `array`):

Limit results to OpenAlex work types such as article, book, dataset, dissertation, preprint, report, or review. Enter a list such as \['article','review']; values are combined as OR within the type filter. This is not a journal or subject category.

## `openAccessOnly` (type: `boolean`):

Set true to keep only works OpenAlex marks as open access. It defaults to false. Open-access status is metadata and may not guarantee that a readable full-text file is available. This is not a license-rights determination.

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

Keep works with at least this OpenAlex cited\_by\_count, for example 50. Leave empty to include all citation counts. Counts reflect OpenAlex metadata and can change over time. This is not a quality or peer-review score.

## `authorId` (type: `string`):

Filter to works linked to one OpenAlex author, using 'A5023888391' or its full URL 'https://openalex.org/A5023888391'. Leave empty to disable. This is an OpenAlex ID, not an ORCID or author name search.

## `institutionId` (type: `string`):

Filter to works associated with one OpenAlex institution, using 'I27837315' or its full URL. Leave empty to disable. This is an OpenAlex institution ID, not a free-text university name.

## `sourceId` (type: `string`):

Filter to works with a location associated with one OpenAlex source ID, such as 'S137773608'. Leave empty to disable. This is an OpenAlex source or journal ID, not an ISSN.

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

Filter to works with an author institution in a two-letter country code such as 'us' or 'gb'. Leave empty to disable. Values are sent lowercase to OpenAlex. This is not the work language or publisher country.

## `hasAbstract` (type: `boolean`):

Set true to keep only works with an abstract indexed by OpenAlex; set false to require no abstract; leave empty to ignore abstract availability. It defaults to empty. This checks metadata availability, not full-text access.

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

Choose result ordering: relevance, citedByCount, or publicationDate; citations and publication date accept a leading '-' for descending order. It defaults to relevance for search and newest publication date for filter-only requests. This is not a custom sort expression.

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

Maximum number of schema-valid work records to store, from 1 to 1,000. It defaults to 25. The actor uses cursor pagination and stops at this cap; it does not download the entire OpenAlex catalog. This is a record cap, not an API page size.

## `perPage` (type: `integer`):

Number of works requested from OpenAlex per API page, from 1 to 100. It defaults to 100 for efficient cursor pagination. Smaller values can reduce response size. This is not the maximum number of output records.

## `responseFormat` (type: `string`):

Choose concise for smaller AI-agent records or detailed for abstracts and fuller author/institution context. It defaults to detailed. Both formats use the same stable field names and output schema. This does not change OpenAlex matching or citation counts.

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

Optional email address sent as the OpenAlex mailto parameter to identify your requests. Enter a normal address such as 'research@example.org'. It defaults to empty. This is not an API key or a notification destination used by Apify.

## Actor input object example

```json
{
  "searchQuery": "machine learning in healthcare",
  "exactSearch": false,
  "advancedFilter": "type:article,has_abstract:true",
  "publicationYearFrom": 2020,
  "publicationYearTo": 2024,
  "workTypes": [
    "article",
    "review"
  ],
  "openAccessOnly": true,
  "minCitations": 50,
  "authorId": "A5023888391",
  "institutionId": "I27837315",
  "sourceId": "S137773608",
  "countryCode": "us",
  "hasAbstract": true,
  "sort": "-citedByCount",
  "maxResults": 25,
  "perPage": 100,
  "responseFormat": "detailed",
  "contactEmail": "research@example.org"
}
```

# Actor output Schema

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

Structured scholarly work records from the default dataset.

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

Compact run diagnostics, record count, page count, filters, and non-fatal warnings.

# 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 = {
    "searchQuery": "machine learning",
    "maxResults": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/openalex-scholarly-works-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 = {
    "searchQuery": "machine learning",
    "maxResults": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/openalex-scholarly-works-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 '{
  "searchQuery": "machine learning",
  "maxResults": 25
}' |
apify call muhammadafzal/openalex-scholarly-works-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/openalex-scholarly-works-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/a4c4tZhbFDm24F72z/builds/7Vc5kOnD1pIBU7rh9/openapi.json
