# Bulk WHOIS and Domain Availability Checker (RDAP) (`boubap/domain-rdap-checker`) Actor

Check up to 10,000 domains a run: taken or free, plus expiry dates and registrar on request. The registry confirms free names for 100 domains per account a day, not on extensions without RDAP (.io, .co, .de); beyond that a free name is "likely-available", not charged. No contact data. $2 per 1,000.

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

## Pricing

from $1.50 / 1,000 domain checkeds

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

## Bulk Domain Availability Checker with RDAP Expiry Dates

Paste domain names, or a few names plus the extensions you want, and get one row per domain: free or taken,
nameservers and, if you ask for it, the registry record with creation and expiry dates, EPP status and registrar.
The record comes from RDAP, the official replacement of WHOIS. Holder data is never returned. Up to 10,000 domains per
run, $2 per 1,000. No API key, no login.

A domain is marked available only when the registry of its extension confirms it over RDAP. DNS alone is not enough:
many registered names have no nameservers (on hold, parked, expired) and look free in DNS. When the registry cannot
confirm, the row says `likely-available` and is not charged.

### What you get

- **Availability**: `available` (the registry answered "not found"), `registered`, `likely-available` (no DNS
  delegation, registry not asked or could not answer; not charged) or `unknown` (DNS and the registry could not tell;
  not charged). `available` is `true`, `false` or `null` for the last two.
- **Nameservers** of taken domains, from DNS.
- **Registry record** (with `includeDates`, or when the registry is asked to confirm): creation, expiry and last update
  dates, EPP status codes such as `client transfer prohibited`, DNSSEC, registrar name and IANA ID. The registrar name
  is given only with a valid IANA registrar ID, so a registry that puts the holder there (Nominet for .uk) gives none.
- **How the answer was found** (`method`: `dns` or `rdap`) and why a registry request was skipped (`rdapStatus`).

The Actor never returns the holder of a domain, contacts, postal addresses or abuse contacts, even when a registry
publishes them.

### Use cases

- Check a brainstorm of brand or product names on .com, .net, .io and your country extension in one run.
- Find the domain expiration date of your own domains, or of domains you want to buy when they drop.
- Clean a list of websites: find the domains that no longer exist before an outreach or a migration.
- Audit a domain portfolio: registrar, EPP locks and DNSSEC for every name.

### Input

| Field | Description | Default |
|---|---|---|
| `domains` | Domain names, up to 10,000 per run. URLs and subdomains are reduced to the registrable domain | |
| `names` | Names without extension, combined with every extension in `tlds` | |
| `tlds` | Extensions for `names`, such as `com`, `io`, `fr` | |
| `includeDates` | Ask the registry RDAP server for the dates, status and registrar of taken domains | `false` |
| `confirmWithRdap` | Ask the registry RDAP server about the domains DNS shows as free. Off: those rows stay `likely-available` | `true` |

Example:

```json
{ "names": ["acme", "acmelabs"], "tlds": ["com", "net", "io"] }
```

### Output

Real output of runs on 28 and 29 October 2026 with `includeDates` on. `eager.com` has no name servers, so DNS alone would call it free: the registry shows it has been registered since 1996. The `.ws` row comes from a run on 28 October:

```json
[
  {
    "domain": "eager.com",
    "tld": "com",
    "available": false,
    "availability": "registered",
    "method": "rdap",
    "nameservers": [],
    "rdapStatus": "ok",
    "status": [
      "client delete prohibited",
      "client transfer prohibited",
      "client update prohibited"
    ],
    "createdAt": "1996-08-27T04:00:00Z",
    "expiresAt": "2027-08-26T04:00:00Z",
    "updatedAt": "2026-07-28T03:49:03Z",
    "registrarName": "Tucows Domains Inc.",
    "registrarIanaId": "69",
    "dnssec": false,
    "rdapServer": "https://rdap.verisign.com/com/v1/",
    "checkedAt": "2026-10-29T00:22:03.409Z",
    "error": null
  },
  {
    "domain": "zz9q-free-test-7k2.com",
    "tld": "com",
    "available": true,
    "availability": "available",
    "method": "rdap",
    "nameservers": [],
    "rdapStatus": "ok",
    "status": [],
    "createdAt": null,
    "expiresAt": null,
    "updatedAt": null,
    "registrarName": null,
    "registrarIanaId": null,
    "dnssec": null,
    "rdapServer": "https://rdap.verisign.com/com/v1/",
    "checkedAt": "2026-10-29T00:22:04.420Z",
    "error": null
  },
  {
    "domain": "zq964e74e2.ws",
    "tld": "ws",
    "available": null,
    "availability": "unknown",
    "method": null,
    "nameservers": [],
    "rdapStatus": "no-rdap-server",
    "status": [],
    "createdAt": null,
    "expiresAt": null,
    "updatedAt": null,
    "registrarName": null,
    "registrarIanaId": null,
    "dnssec": null,
    "rdapServer": null,
    "checkedAt": "2026-10-28T08:18:55.931Z",
    "error": ".ws answers every name (wildcard): DNS cannot tell whether this one is registered"
  }
]
```

### Sources, speed and limits

- **DNS**: a nameserver lookup for every domain, 10 at a time. In a test run, 1,000 domains took 39 seconds.
- **RDAP**: the official registry server of each extension, taken from the
  [IANA list](https://data.iana.org/rdap/dns.json). Verisign answers for .com and .net, Public Interest Registry for
  .org, and so on. Extensions without an RDAP server (.de, .io, .co, .es, .it, .eu, .ch among others) get the DNS answer
  only, with `rdapStatus` `no-rdap-server`: free-looking names there stay `likely-available`. If the IANA list cannot
  be loaded, the whole run works that way and says so in the log.
- Registry requests go out at most one per second per registry and 100 per account per day (UTC), retries included.
  Past this limit the domains keep their DNS answer, with `rdapStatus` `cap-reached`.
- Some extensions (.ws, .ph) answer every name in DNS. The Actor tests one random name per extension and run; on such
  an extension a name without nameservers is `unknown` unless the registry answers.
- If a registry answers "too many requests" (HTTP 429 or 403), the run sends it nothing more and the next domains on
  it get `rdapStatus` `rate-limited`. The Actor never works around such a limit and never queries registrar servers.

### Pricing

$0.002 per domain ($2 per 1,000), with volume discounts for higher Apify plans. The registry options cost nothing
extra. Rows with `availability` `likely-available` or `unknown` are free, and duplicates are removed before checking. Set a maximum cost
per run in the Apify Console to cap the spend.

### Integrations

Run it from the Apify API, a schedule, Make, Zapier or n8n and send the rows to Google Sheets, Airtable or a database.
A weekly schedule with `includeDates` on your own domains is an easy expiry reminder.

### FAQ

**Is a domain shown as free really free?** `available` means the registry has no record of it. DNS alone is not
reliable: in a test on 1,000 domains (200 common English words on .com, .net, .org, .io and .fr), DNS showed 15 as
free and all 15 were registered. That is why such names are only `likely-available` until the registry confirms. A
confirmed name can still be reserved or sold at a premium price, so check at your registrar before you buy. Names under
zones kept for eligible bodies (gouv.fr, gov.uk, ac.uk, nhs.uk, .gov, .edu and similar) are never `available`: at best
`likely-available`, not charged, with the reason in `error`.

**Why do some rows have no dates?** The extension has no RDAP server, the option was off, or the run or daily
registry limit was reached. `rdapStatus` tells which.

**Does it return WHOIS contacts?** No. It never outputs holder, contact, address or abuse data.

**Can I enter subdomains?** Yes, but only the registrable domain is checked, from the Public Suffix List:
`blog.example.co.uk` gives one row for `example.co.uk`.

### Related Actors

- [Tech Stack Detector](https://apify.com/boubap/tech-stack-detector): the technologies behind the websites of the
  domains that are taken.
- [Broken Links Checker](https://apify.com/boubap/broken-links-checker): find dead links on a site, then check whether
  the linked domains still exist.

# Actor input Schema

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

Domain names to check, one per line, for example "apify.com". Full URLs and subdomains are accepted: each entry is reduced to its registrable domain (blog.example.co.uk becomes example.co.uk). Up to 10,000 domains per run; duplicates are removed.

## `names` (type: `array`):

Optional. Names without extension, for example "acme". Each one is checked on every extension listed in "tlds".

## `tlds` (type: `array`):

Extensions to combine with "names", for example "com", "io", "fr". Not used without "names".

## `includeDates` (type: `boolean`):

For taken domains, also ask the official RDAP server of the registry for the creation, expiry and update dates, the EPP status and the registrar. Slower (one request per second per registry). Shares the daily limit of 100 registry requests per account with the confirmation option, retries included.

## `confirmWithRdap` (type: `boolean`):

For domains that DNS shows as free, ask the RDAP server of the registry. A domain is marked available only when the registry confirms it: many registered names have no nameservers and look free in DNS. Without confirmation (option off, extension without RDAP, daily limit) a free-looking domain is "likely-available" and not charged. Same limits as the dates option.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "example.org",
    "a-domain-that-does-not-exist-7f3k.com"
  ],
  "includeDates": false,
  "confirmWithRdap": true
}
```

# Actor output Schema

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

Dataset items of the run: one item per result, with the fields described in the dataset schema.

# 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",
        "a-domain-that-does-not-exist-7f3k.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("boubap/domain-rdap-checker").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",
        "a-domain-that-does-not-exist-7f3k.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("boubap/domain-rdap-checker").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",
    "a-domain-that-does-not-exist-7f3k.com"
  ]
}' |
apify call boubap/domain-rdap-checker --silent --output-dataset

```

## MCP server setup

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

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/5hJuPof073Wl46agr/builds/Tr6HzbUg5gFJKIPDF/openapi.json
