# Bulk Domain Availability Checker (RDAP) (`isnard/domain-availability-checker`) Actor

Check if domains are available or registered using official RDAP registry data, with a DNS check as a second signal. Give a list of domains or combine names with TLDs. Returns registrar, creation and expiry dates.

- **URL**: https://apify.com/isnard/domain-availability-checker.md
- **Developed by:** [Matias Isnard](https://apify.com/isnard) (community)
- **Categories:** Developer tools
- **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.

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 (RDAP)

Check a list of domains and find out which are registered and which look available. Give it full domains, or a list of names and a list of TLDs to combine (for example `acme`, `getacme` with `.com`, `.io`, `.com.ar` gives six domains).

Each domain is looked up in the official registry data through RDAP, the standard that replaces WHOIS. A DNS nameserver lookup runs alongside as a second signal. For registered domains you also get the registrar, creation date, expiry date and status codes.

No registrar website is scraped. The only hosts contacted are the IANA bootstrap file, the registry RDAP servers it lists, and public DNS resolvers (1.1.1.1 and 8.8.8.8).

### Who it is for

- **Naming a product or company**: test dozens of name ideas across several extensions in one run.
- **Domain investors**: check expiry dates and registrars of a portfolio or a watch list.
- **Brand protection**: see which variations of your brand under other TLDs are already taken.
- **Agencies**: check client domains for upcoming expiry.

### How the answer is decided

1. The TLD is looked up in the IANA RDAP bootstrap file (`https://data.iana.org/rdap/dns.json`), which lists the RDAP server of each registry. The longest matching suffix wins, so `.com.ar` uses its own entry when one exists.
2. The Actor asks that server for the domain.
   - HTTP 200: the domain is **registered**. Dates, registrar and status come from this answer.
   - HTTP 404: the registry has no record of it. The domain is reported as **available**, unless DNS shows nameservers for it (then it is reported as registered, because the name is clearly in use).
   - HTTP 429 (rate limited): the Actor waits (using the `Retry-After` header when the server sends one, otherwise 2, 4, 8 seconds) and tries again, up to 4 attempts.
   - Anything else, a timeout or no RDAP server for the TLD: the answer comes from DNS only.
3. DNS only: nameservers or any record mean **registered**. No record at all (NXDOMAIN) means **available**, but with lower confidence, because a registered domain without nameservers looks the same.

Every result has a `confidence` field:

| confidence | meaning |
| --- | --- |
| `rdap` | The registry RDAP server answered. This is the strongest signal available without a registrar account. |
| `dns-only` | No usable RDAP answer. Decided from DNS. Reliable for "registered", weak for "available". |
| `none` | Neither source answered. Status is `unknown`. |

#### "Available" is never a guarantee

RDAP tells you whether a registration record exists. It does not tell you whether the registry will sell the name to you, or at what price. Premium names, names reserved by the registry, blocked trademarks and names in a grace or redemption period can show as available here and still not be purchasable at the normal price. Always confirm at a registrar before you buy. Every `available` result carries a note saying this.

### Input

```json
{
    "domains": ["google.com", "mercadolibre.com.ar"],
    "names": ["acme", "getacme"],
    "tlds": [".com", ".io", ".com.ar"],
    "concurrency": 10
}
```

- `domains`: full domains or URLs. URLs are reduced to the hostname and a leading `www.` is removed.
- `names` and `tlds`: every name is combined with every TLD. The leading dot is optional.
- `concurrency` (default 10, max 50): domains checked in parallel. Independently of this, at most 2 requests run at the same time against any one RDAP server, so a large `.com` list does not hammer Verisign.

You can use `domains`, `names` + `tlds`, or both. Duplicates are checked once. Invalid entries are skipped with a warning in the log and are not charged. Up to 10,000 domains per run.

### Output

One dataset item per domain. Real output for 10 domains is in `ejemplos/salida.json` in the source.

```json
{
    "input": "google.com",
    "domain": "google.com",
    "status": "registered",
    "confidence": "rdap",
    "note": null,
    "registered_at": "1997-09-15T04:00:00Z",
    "expires_at": "2028-09-14T04:00:00Z",
    "last_changed_at": "2019-09-09T15:39:04Z",
    "registrar": "MarkMonitor Inc.",
    "rdap_status": ["client delete prohibited", "client transfer prohibited", "..."],
    "dns_nameservers": ["ns1.google.com", "ns2.google.com", "ns3.google.com", "ns4.google.com"],
    "dns_result": "delegated",
    "rdap_server": "https://rdap.verisign.com/com/v1/",
    "rdap_http_status": 200,
    "checked_at": "2026-10-29T09:25:38+00:00",
    "errors": []
}
```

An available domain:

```json
{
    "domain": "qzvx7plmk.com",
    "status": "available",
    "confidence": "rdap",
    "note": "Not found in the registry. Premium, reserved or blocked names can still look available. Confirm at a registrar before buying.",
    "registrar": null,
    "dns_result": "nxdomain",
    "rdap_http_status": 404,
    "errors": []
}
```

`dns_result` is `delegated` (NS records found), `exists` (the name exists but has no NS records, typical for a subdomain), `nxdomain` or `error`. Problems are listed in `errors` for that domain instead of failing the run.

### Pricing

Pay per event: you pay for each domain that got a definitive answer (`domain-checked` event), that is every `available` or `registered` result, from RDAP or from DNS. Domains with status `unknown` and invalid input lines are not charged. You can cap the cost of a run with the "Maximum cost per run" setting; the Actor stops cleanly when the cap is reached.

### Limitations

- Some TLDs have no RDAP server in the IANA bootstrap file (at the time of writing this includes `.io`, `.co` and `.de` and many other country codes). Those are checked with DNS only, see `confidence`.
- Some RDAP servers are slow or time out (15 seconds per request). Those domains fall back to DNS only.
- Registries limit how fast one IP can query them. Very large runs against a single TLD can still hit limits; the Actor slows down and retries, and reports `unknown` if the server keeps refusing.
- For `.com` and `.net` the registry answer contains the registrar and dates but not the registrant. Registrant data is not collected.
- Internationalized domain names must be given in punycode form (`xn--...`).
- Results are a snapshot at the time of the run. A domain can be registered by someone else a minute later.

### Run locally

```bash
python -m venv .venv
.venv/Scripts/pip install -r requirements.txt   # on Linux/macOS: .venv/bin/pip
## put input in storage/key_value_stores/default/INPUT.json
.venv/Scripts/python -m my_actor
python -m unittest discover -s tests -t .
```

Author: Matias Isnard.

# Actor input Schema

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

Full domains to check, one per line (for example acme.com). URLs are reduced to their hostname and a leading www. is removed. Can be combined with names and TLDs below. Duplicates are checked once.

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

Names without extension (for example acme, getacme). Each name is combined with every TLD below.

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

Extensions to combine with the names, with or without the leading dot (for example .com, .io, .com.ar).

## `concurrency` (type: `integer`):

Domains checked in parallel. Requests to the same registry RDAP server are additionally limited to 2 at a time and slow down when the server answers HTTP 429.

## Actor input object example

```json
{
  "domains": [
    "google.com",
    "example.org"
  ],
  "concurrency": 10
}
```

# Actor output Schema

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

No description

# 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": [
        "google.com",
        "example.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("isnard/domain-availability-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": [
        "google.com",
        "example.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("isnard/domain-availability-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": [
    "google.com",
    "example.org"
  ]
}' |
apify call isnard/domain-availability-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,isnard/domain-availability-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/NSS1LvluntC38yEWw/builds/EsEAIOIsEuRaFf61C/openapi.json
