# Bulk Domain Availability & WHOIS Lookup (RDAP): Expiry, DNS (`ailu_studio/rdap-domain-lookup`) Actor

Bulk domain availability and WHOIS-style lookup over RDAP: registered or available, registrar and IANA ID, registration and expiry dates, days to expiry, status, nameservers and DNSSEC for any list of domains. Public rdap.org bootstrap, no API key.

- **URL**: https://apify.com/ailu_studio/rdap-domain-lookup.md
- **Developed by:** [Ailu Studio](https://apify.com/ailu_studio) (community)
- **Categories:** Developer tools, SEO tools, Agents
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 successful lookups

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/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

## Bulk Domain Availability & WHOIS Lookup (RDAP): Expiry, Registrar, DNS

Check any list of domains in bulk and get clean JSON for each: whether the domain is registered or available, the sponsoring registrar and its IANA ID, registration and expiry dates, days to expiry, EPP status codes, nameservers and DNSSEC. The Actor uses RDAP, the structured, JSON-based successor of WHOIS that ICANN requires every gTLD registry to run, through the public rdap.org bootstrap server, which redirects each query to the registry responsible for the TLD. No API key, no browser, no WHOIS text parsing. Every row has a stable `id`, free rows for unsupported TLDs and errors never fail the run, and the defaults return results in a few seconds.

### Use cases

- Bulk availability checks for domain investors, brand-name brainstorming and product naming (hundreds of candidate names in one run).
- Expiry monitoring for your own portfolio or your clients' domains: schedule the Actor and alert on low `daysToExpiry`.
- Brand protection: watch look-alike and typo domains and detect when one becomes registered, changes registrar or changes nameservers.
- Lead enrichment and due diligence: registration age, registrar and DNSSEC status for a list of company domains.
- Replace fragile WHOIS scraping in AI agents and pipelines with structured RDAP data.

### Input

| Field | Default | Meaning |
|---|---|---|
| `domains` | `["apify.com", "example.org", "this-domain-is-surely-free-98213.com"]` | Domain names to look up. URLs and host names are accepted: scheme, path, port, whitespace, `www.` and sub-domains are stripped down to the registrable domain (`news.bbc.co.uk` becomes `bbc.co.uk`). Internationalised names are converted to punycode. Duplicates are looked up once. |
| `maxItems` | `300` | Maximum number of charged rows (successful lookups). Free rows do not count. Lookups stop once the limit is reached. |

Example input:

```json
{ "domains": ["apify.com", "https://www.bbc.co.uk/news", "münchen.com", "my-new-brand-name.com", "example.de"], "maxItems": 500 }
```

### Output

One row per unique domain. A lookup is successful (charged) when a registry RDAP server answered: either with the domain object (registered) or with 404 (not registered, i.e. available). Rows for TLDs without RDAP, invalid names and lookup errors are free.

| Field | Type | Meaning |
|---|---|---|
| `id` | string | Stable key `rdap:<domain>`. |
| `domain` | string | Registrable domain that was queried, lower-case, punycode for IDNs. |
| `inputDomain` | string | Cleaned input before reduction to the registrable domain. |
| `tld` | string | null | Top-level domain, e.g. `com`. |
| `isRegistered` | boolean | null | True when the registry returned a domain object, false on a registry 404, null when unknown. |
| `isAvailable` | boolean | null | `!isRegistered` when an RDAP server exists for the TLD, otherwise null. |
| `rdapAvailable` | boolean | null | True when rdap.org redirected to a registry server for this TLD; false when the TLD has no RDAP service or the name is invalid; null when the request failed before that was known. |
| `registrar` | string | null | Sponsoring registrar name. |
| `registrarIanaId` | integer | null | IANA registrar ID when published (ccTLD registries often omit it). |
| `status` | string\[] | EPP/RDAP status values, e.g. `["client transfer prohibited"]`. |
| `nameservers` | string\[] | Nameserver host names, lower-case. |
| `registrationDate` | ISO 8601 | null | Registration date. |
| `expirationDate` | ISO 8601 | null | Expiry date. |
| `lastChangedDate` | ISO 8601 | null | Last change to the registration. |
| `rdapDbUpdatedAt` | ISO 8601 | null | Last update of the registry's RDAP database. |
| `daysToExpiry` | integer | null | Whole days until `expirationDate`; negative when past. |
| `dnssecSigned` | boolean | null | DNSSEC delegation signed, when the registry publishes it. |
| `rdapServer` | string | null | Registry RDAP host that answered, e.g. `rdap.verisign.com`. |
| `error` | string | null | Null on success; otherwise a short reason. |
| `fetchedAt` | ISO 8601 | Time of the lookup. |

Sample row:

```json
{
  "id": "rdap:apify.com", "domain": "apify.com", "inputDomain": "apify.com", "tld": "com",
  "isRegistered": true, "isAvailable": false, "rdapAvailable": true,
  "registrar": "Amazon Registrar, Inc.", "registrarIanaId": 468, "status": ["client transfer prohibited"],
  "nameservers": ["ns-1225.awsdns-25.org", "ns-1928.awsdns-49.co.uk", "ns-449.awsdns-56.com", "ns-839.awsdns-40.net"],
  "registrationDate": "2009-06-02T17:14:10.000Z", "expirationDate": "2035-06-02T17:14:10.000Z",
  "lastChangedDate": "2026-05-16T16:53:04.000Z", "rdapDbUpdatedAt": "2026-11-03T15:17:49.000Z",
  "daysToExpiry": 3133, "dnssecSigned": true, "rdapServer": "rdap.verisign.com", "error": null,
  "fetchedAt": "2026-11-03T15:18:00.555Z"
}
```

An available domain looks like `{ "domain": "my-new-brand-name.com", "isRegistered": false, "isAvailable": true, "rdapAvailable": true, "rdapServer": "rdap.verisign.com", "error": null, ... }` with the other fields null or empty. A TLD without RDAP looks like `{ "domain": "example.de", "isRegistered": null, "isAvailable": null, "rdapAvailable": false, "error": "No RDAP service for .de ..." }`.

The run summary (counts of registered, available, no-RDAP, invalid and failed lookups, errors, request and retry counts) is stored in the `OUTPUT` record of the default key-value store.

### How it works and limits

- RDAP vs WHOIS: WHOIS returns free-form text that differs per registry; RDAP (RFC 9082/9083) returns JSON with standard fields, so registrar, dates, status and nameservers are read without parsing heuristics. All gTLDs (.com, .net, .org, .io-style new gTLDs, ...) must run RDAP; many ccTLDs do (.uk, .kr, .fr, .nl, .ch, .br and more) but some do not (for example .de, .jp, .au, .io at the time of writing). For those the row says `rdapAvailable: false` and no availability claim is made.
- Each domain is one request to `https://rdap.org/domain/<domain>`, which redirects to the registry's RDAP server (`rdapServer`). A registry 404 means the name is not registered. Registrant and contact details are mostly redacted by registries since GDPR and are not returned.
- Rate: lookups run one at a time, spaced at least 700 ms apart (rdap.org allows 10 requests per 10 seconds; registries throttle too). 429 and 5xx responses are retried with backoff. 100 domains take roughly 1.5-2 minutes.
- Registries throttle and occasionally time out; such rows are free, carry an `error` and the run status becomes `partial`. Re-run the failed domains later.
- "Available" means the registry has no record for the name. Reserved, premium and registry-blocked names can still be impossible or expensive to register; verify at a registrar before buying.
- Not covered: registrant contact data, historical WHOIS, pricing, DNS record lookups (A/MX), sub-domain existence (inputs are reduced to the registrable domain) and TLDs without an RDAP server.

### Pricing

Pay per result: **$2.00 per 1,000 successful lookups** (`result` event). Platform usage is billed separately by Apify. Removed/free rows are not charged.

### Legal

Not affiliated with rdap.org, ICANN, Verisign or any registry. Uses the public rdap.org bootstrap service and the registries' public RDAP servers only. Data licence/terms: https://about.rdap.org/ and each registry's RDAP terms of service (for .com/.net: https://www.verisign.com/domain-names/registration-data-access-protocol/terms-service/index.xhtml). Use the data only for lawful purposes; registries forbid using it for unsolicited marketing.

### FAQ

**Why is a domain reported as not registered although it resolves?** Make sure you passed the registrable domain of a TLD with RDAP; the Actor reduces host names (`shop.example.com`) to `example.com`, but for second-level ccTLD suffixes it only knows the common ones (`co.uk`, `com.au`, `co.jp`, ...). Also, some registries answer 404 for names that are blocked or reserved.

**What does `rdapAvailable: false` mean?** The rdap.org bootstrap has no RDAP server for that TLD, so neither availability nor registration data can be determined. Those rows are free. Use a WHOIS-based tool for such TLDs.

**Is `isAvailable: true` a guarantee I can buy the domain?** No. It means the registry has no registration record right now. Premium and reserved names, pending deletes and registry policies can still prevent registration; check at a registrar.

**How many domains can I check in one run?** As many as you like; set `maxItems` accordingly. At 700 ms per lookup 1,000 domains take about 12-15 minutes. Very large lists are best split into several runs to keep registries happy.

**Why is `registrarIanaId` or `expirationDate` missing for some ccTLDs?** ccTLD registries publish what their policy allows; for example Nominet (.uk) lists the registrar without an IANA ID, and some registries omit expiry dates. The fields are null in that case.

# Actor input Schema

## `domains` (type: `array`):

Domain names to look up, one per line, e.g. "apify.com" or "example.co.uk". URLs and host names are accepted: scheme, path, port, "www." and sub-domains are stripped down to the registrable domain. Internationalised names are allowed. Duplicates are removed.

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

Upper limit on charged rows (successful lookups: registered or available). Free rows (unsupported TLD, invalid name, lookup error) do not count. Lookups stop once the limit is reached. Default 300.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "example.org",
    "this-domain-is-surely-free-98213.com"
  ],
  "maxItems": 300
}
```

# Actor output Schema

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

All rows in the default dataset.

# 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 = {
    "domains": [
        "apify.com",
        "example.org",
        "this-domain-is-surely-free-98213.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ailu_studio/rdap-domain-lookup").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 = { "domains": [
        "apify.com",
        "example.org",
        "this-domain-is-surely-free-98213.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ailu_studio/rdap-domain-lookup").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 '{
  "domains": [
    "apify.com",
    "example.org",
    "this-domain-is-surely-free-98213.com"
  ]
}' |
apify call ailu_studio/rdap-domain-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ailu_studio/rdap-domain-lookup"
        }
    }
}
```

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/dbVasPOvdfZyQ441A/builds/JS4huVH6noyOwxbr7/openapi.json
