# Ror Research Organizations Scraper (`zerobreak/ror-research-organizations-scraper`) Actor

ROR Research Organizations Scraper extracts metadata from the Research Organization Registry (ROR) API. Easily pull institutional names, ROR IDs, locations, and organizational hierarchies into structured formats for bibliographic research.

- **URL**: https://apify.com/zerobreak/ror-research-organizations-scraper.md
- **Developed by:** [ZeroBreak](https://apify.com/zerobreak) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 results

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

## ROR Research Organizations Scraper

<p align="center"><img src="https://imgur.com/mQg5Us1.png" alt="ROR Research Organizations Scraper" width="800" /></p>

ROR Research Organizations Scraper collects university and research organization records from the public Research Organization Registry (ROR) API. Search by organization name or look up specific ROR IDs, then export organization names, domains, locations, identifiers, and related records as JSON, CSV, or Excel.

No login or API key is required.

### Use Cases

- **University lists:** Search for organizations by name, such as `oxford`, and export matching institutions.
- **Known ROR IDs:** Retrieve specific organizations using IDs obtained from research papers, grant records, or other sources.
- **Affiliation cleanup:** Collect display names, aliases, and domains to help standardize author affiliations.
- **Scheduled refreshes:** Repeat searches to keep organization datasets up to date.
- **Free registry exports:** Access public organization records without requiring an API key.

### Input

| Parameter | Type | Default | Description |
|---|---|---|---|
| `query` | string | `oxford` | Organization name used for the search. Leave blank when looking up only specific ROR IDs. |
| `rorIds` | array | Empty | ROR IDs to retrieve, one per entry. Accepts nine-character IDs or full ROR URLs. |
| `maxItems` | integer | `100` | Maximum dataset rows, including error rows. Hard limit: 1,000. |
| `timeoutSecs` | integer | `300` | Maximum time allowed for starting new ROR requests. |
| `requestTimeoutSecs` | integer | `30` | Timeout in seconds for each HTTP request. |

#### Example Input

```json
{
  "query": "oxford",
  "rorIds": ["052gg0110"],
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30
}
```

### What Data Does This Actor Extract?

Each organization is saved as one dataset row. Search results use organization records from the ROR v2 search response, while direct ID lookups return the corresponding organization object.

Names retain their original spelling, including non-English labels, after HTML tags are removed.

#### Example Output

```json
{
  "admin": {
    "created": {
      "date": "2018-11-14",
      "schema_version": "1.0"
    },
    "last_modified": {
      "date": "2026-09-22",
      "schema_version": "2.1"
    }
  },
  "domains": ["ox.ac.uk"],
  "established": 1096,
  "external_ids": [
    {
      "all": ["grid.4991.5"],
      "preferred": "grid.4991.5",
      "type": "grid"
    }
  ],
  "id": "https://ror.org/052gg0110",
  "links": [
    {
      "type": "website",
      "value": "https://www.ox.ac.uk"
    }
  ],
  "locations": [
    {
      "geonames_id": 2640729,
      "geonames_details": {
        "name": "Oxford",
        "country_name": "United Kingdom"
      }
    }
  ],
  "names": [
    {
      "lang": "en",
      "types": ["alias"],
      "value": "Oxford University"
    },
    {
      "lang": "cy",
      "types": ["label"],
      "value": "Prifysgol Rhydychen"
    }
  ],
  "relationships": [],
  "status": "active",
  "types": ["education"],
  "sourceUrl": "https://api.ror.org/v2/organizations/052gg0110",
  "scrapedAt": "2026-10-12T00:00:00+00:00"
}
```

#### Output Fields

| Field | Type | Description |
|---|---|---|
| `admin` | object | Creation and last-modified dates supplied by the source. |
| `domains` | array | Organization domain names. |
| `established` | integer | Year the organization was established, when provided as a number. |
| `external_ids` | array | External identifiers, such as GRID, Wikidata, or FundRef IDs. |
| `id` | string | Organization's ROR identifier URL. Duplicate ROR IDs are skipped. |
| `links` | array | Website and Wikipedia links. |
| `locations` | array | GeoNames location objects. |
| `names` | array | Organization labels and aliases, with HTML tags removed. |
| `relationships` | array | Parent, child, and other related organizations. |
| `status` | string | Organization status reported by ROR, usually `active`. |
| `types` | array | Organization classifications, such as education or nonprofit. |
| `sourceUrl` | string | ROR API URL used for the request. |
| `scrapedAt` | string | UTC timestamp when the row was stored. |
| `error` | string | Present only when a request or ID fails. |
| `input` | string | Query or ROR ID associated with an error row. |

Failed requests generate rows containing `error`, `input`, `sourceUrl`, and `scrapedAt`. The run continues instead of failing entirely.

If a search returns no matches, the actor saves one row explaining that no organizations matched rather than returning an empty dataset.

### How It Works

1. Reads the organization search query, ROR IDs, item limit, and timeout settings.
2. Retrieves requested ROR IDs first when provided.
3. Searches for organizations by name when a query is provided.
4. Extracts the source organization fields and adds `sourceUrl` and `scrapedAt`.
5. Skips duplicate ROR IDs.
6. Continues pagination until all reported search results are covered, a page contains fewer results than expected, or the item limit is reached.
7. Saves error records for failed requests, invalid IDs, and unsuccessful searches.

### Pagination and Limits

- **Search pagination:** Uses pages containing up to 20 organizations.
- **Maximum results:** A run can save up to 1,000 rows, including error rows.
- **Request frequency:** Waits 0.2 seconds between requests, targeting no more than five requests per second.
- **Published API limit:** The actor's documented request pace is below the stated ROR limit of 2,000 requests per five minutes per IP.
- **Duplicate handling:** Duplicate ROR IDs are discarded.
- **Request retries:** HTTP 429 responses, HTTP 5xx responses, and timeouts are retried three times with waits of 2, 4, and 8 seconds. A `Retry-After` header overrides the wait when provided.
- **Other HTTP errors:** Other 4xx responses are not retried.
- **Invalid IDs:** IDs that do not contain exactly nine letters or digits are saved as error rows and are not requested.
- **Invalid response bodies:** HTTP 200 responses that do not contain valid JSON are handled as errors.
- **Combined input:** When both `rorIds` and `query` are provided, ID lookups run first, followed by the name search, until the row limit is reached.

### Data Source

Organization records come from the public ROR v2 organizations API. The actor supports name-based searches and direct organization lookups.

Each successful record includes `sourceUrl` so you can trace the extracted data to the request that returned it.

ROR data is released under CC0, and registration is not required to use the public API. ROR recommends a client ID for frequent API usage.

### FAQ

**Does this ROR research organizations scraper need an API key?**

No. Organization searches and individual ROR ID lookups use the public API and do not require an API key.

**How do I look up one university?**

Add its nine-character ROR ID to `rorIds`, such as `052gg0110`. Clear `query` if you only want the ID lookup without a name search.

**Why did I get an error row?**

An invalid ID is rejected before a request is sent. A missing organization may return HTTP 404. A response containing HTML instead of JSON is recorded as an error, and a search with no matches produces a row explaining that no organizations matched.

**Can I export JSON, CSV, and Excel?**

Yes. Run the actor and download the dataset in JSON, CSV, or Excel format.

**Can I search by name and look up IDs in the same run?**

Yes. The actor processes ROR ID lookups first, then performs the organization-name search, subject to the maximum row limit.

**Does the actor use a proxy by default?**

No. The default configuration uses a direct connection. Respect ROR's rate limits and do not use a proxy to evade them.

### Pricing

The actor is free to run. Normal Apify platform usage charges may still apply.

### Trademark Notice

ROR and related names, logos, and trademarks belong to their respective owners. Their use in this documentation is solely to identify the data source and does not imply affiliation, sponsorship, endorsement, or partnership.

### Disclaimer

This actor is an independent tool and is not affiliated with, endorsed by, sponsored by, or officially associated with ROR or its owners. Data is collected from publicly available sources. Users are responsible for complying with the source's terms of use, rate limits, attribution requirements, and applicable licensing conditions.

### Is Web Scraping Legal?

This actor collects publicly available organization data through the ROR API without logging in or bypassing access controls. The legality of collecting and using public data depends on the circumstances and applicable laws.

- **Personal data:** If records contain personal data, privacy laws such as the GDPR or CCPA may apply. Collect and retain personal data only when you have an appropriate legal basis.
- **Copyright:** Some content may be protected by copyright. Check the applicable licensing conditions before republishing protected material.
- **Terms of use:** Respect the source's terms, published request limits, and applicable attribution or licensing requirements.
- **Legal advice:** This information is general guidance, not legal advice. Consult a qualified lawyer if you are unsure about your obligations.
  To learn more, read Apify's guide: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

# Actor input Schema

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

Organization name sent to the public ROR v2 search. The default, oxford, matches the verified organizations search. Leave this blank when you only want the ROR ids list.

## `rorIds` (type: `array`):

Specific ROR ids to look up, one per line. Use the nine-character id or a full https://ror.org/ URL, for example 052gg0110.

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

Maximum dataset rows for this run, including error rows. Values above 1000 are clamped to 1000.

## `timeoutSecs` (type: `integer`):

Stop starting new ROR requests after this many seconds. This does not replace the Apify run timeout.

## `requestTimeoutSecs` (type: `integer`):

Seconds to wait for a single ROR HTTP response before retrying.

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

Optional proxy for ROR requests. The default sends traffic directly, with no Apify Proxy. Do not use proxies to get around the ROR rate limit.

## Actor input object example

```json
{
  "query": "oxford",
  "rorIds": [
    "052gg0110"
  ],
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `datasetUrl` (type: `string`):

API URL for the default dataset of this run.

## `datasetItemsUrl` (type: `string`):

Item list for the default dataset.

## `overviewUrl` (type: `string`):

Overview table of organization records.

# 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": "oxford",
    "rorIds": [],
    "maxItems": 100,
    "timeoutSecs": 300,
    "requestTimeoutSecs": 30,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("zerobreak/ror-research-organizations-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": "oxford",
    "rorIds": [],
    "maxItems": 100,
    "timeoutSecs": 300,
    "requestTimeoutSecs": 30,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("zerobreak/ror-research-organizations-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": "oxford",
  "rorIds": [],
  "maxItems": 100,
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call zerobreak/ror-research-organizations-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zerobreak/ror-research-organizations-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/bRoRBvkUh7mNmNxL7/builds/mrEfB5t268h5OJVh1/openapi.json
