# RDAP Domain Lookup: Expiry Dates & Registrar (`kelp_forest_labs/rdap-domain-lookup`) Actor

Look up many domains at once over RDAP, the official successor of WHOIS: expiry, creation and update dates, registrar, nameservers, status codes and DNSSEC. No registrant or contact data. Unregistered and failed lookups are free.

- **URL**: https://apify.com/kelp_forest_labs/rdap-domain-lookup.md
- **Developed by:** [kelp forest](https://apify.com/kelp_forest_labs) (community)
- **Categories:** Developer tools, SEO 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 looked ups

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

Look up a list of domains over **RDAP**, the official, machine-readable successor of WHOIS, and get one clean row per
domain: expiry, creation and last-update dates, registrar, nameservers, RDAP status values and whether DNSSEC is on.
Only non-personal fields are returned: no registrant names, emails, phone numbers or addresses. Domains the registry
does not know (often unregistered) and failed lookups are free.

### Use cases

- **Domain portfolios and agencies:** see every expiry date and registrar in one table before renewals.
- **SEO and marketing teams:** check that client or campaign domains are registered, not expiring and not locked out.
- **Security and IT teams:** spot domains without DNSSEC, with unexpected nameservers or in `client hold` / `pending delete` status.
- **Developers:** a simple JSON API for domain facts, without parsing WHOIS text.

### What it does

- Finds the right registry RDAP server for each TLD from IANA's official RDAP bootstrap file and asks it for the
  domain record (`GET <server>/domain/<name>`). If the IANA file cannot be read, it uses the public rdap.org redirector.
- Returns per domain: `registered`, `expires`, `created`, `updated`, `registrar` (organisation name) and
  `registrarIanaId`, `nameservers`, `dnssecSigned`, `domainStatus` (RDAP status values such as `client transfer prohibited`),
  `unicodeName` for international domains, and the `rdapUrl` that was asked.
- Accepts plain domains, international names (converted to punycode with IDNA 2008, so `straße.de` stays
  `xn--strae-oqa.de`) and URLs. Subdomains are reduced to the registered domain with the public suffix list, because
  registries only hold registered domains: `https://www.example.com/page` and `blog.example.co.uk` look up
  `example.com` and `example.co.uk`. The original text stays in `input`. Duplicates are looked up once.
- Looks up at most `maxDomains` unique domains per run (default 1,000, maximum 10,000); the rest are not looked up and
  not charged, and the count is in `SUMMARY`. For .com and .net (Verisign) the cap is 500 per run; extra .com/.net
  domains become free `skipped` rows.
- Only uses an answer that is about the domain you asked for: if the registry redirects or returns a record whose
  `ldhName` is a different domain, the row is a free `mismatch` row and the other domain's data is not used.

### Polite by design

- Identifies itself as `KelpForestLabs-RDAP` with a link to our Apify profile; it never pretends to be a browser.
- Uses only the official RDAP JSON interface (RFC 9082/9083), one request at a time, with a gap between requests to
  the same registry server (at least 1 s, whatever `delaySecs` says). It does not retry when a server says it is rate limited (HTTP 429), and it stops querying that server for the
  rest of the run: its remaining domains become free `skipped` rows.
- **Registry terms apply.** Each registry's RDAP terms of use apply to the data; use it lawfully, not for spam, and
  keep lists to what you need. Some registries restrict bulk use: Verisign (.com, .net), for example, forbids using its
  data to enable high-volume, automated processes that query its systems, so this actor caps .com/.net at 500 domains per run and keeps at least 1 s between requests to each registry.
- Private and internal network addresses are refused on every request and redirect.

### Pricing (pay per event)

| Event | Price |
|---|---|
| `domain` (one domain whose RDAP record was found and returned) | US$0.0015 |

**Not found and failed lookups are free:** domains the registry has no record of, invalid input, TLDs without an
RDAP service, rate limits, mismatched answers, domains over `maxDomains` or the .com/.net cap, timeouts and server errors give a free row. 1,000 found domains cost US$1.50.

Each run also has Apify's run-start charge of US$0.00005, once per run for up to 1 GB of memory plus once per extra GB (US$0.00005 at the default 256 MB),
charged when the run starts. You can set a maximum charge per run in the Apify Console; the actor stops before the
first domain it could not be paid for.

### How to use

1. Paste your domains into **Domains** (one per line).
2. Run the actor and open the **Domains** view, or export it as CSV, Excel or JSON.
3. Open the `SUMMARY` record for the counts (found, not found, errors, skipped, over `maxDomains`).

### Input example

```json
{"domains": ["apify.com", "example.com", "iana.org"]}
```

### Output example (test fixture, Oct 13, 2026; trimmed; `rdapUrl` shown as for the .com registry)

```json
{"domain": "example.com", "status": "ok", "event": "domain", "registered": true,
 "created": "1995-08-14T04:00:00Z", "updated": "2026-08-14T07:01:39Z", "expires": "2027-08-13T04:00:00Z",
 "registrar": "Example Registrar Inc.", "registrarIanaId": "376", "nameservers": ["a.iana-servers.net", "b.iana-servers.net"],
 "dnssecSigned": true, "domainStatus": ["client delete prohibited", "client transfer prohibited"],
 "rdapUrl": "https://rdap.verisign.com/com/v1/domain/example.com", "httpStatus": 200}
```

### FAQ

**Is "not found" the same as available?**
Usually, but not always: some registries hide reserved or blocked names. Check with a registrar before you buy.

**Why is a TLD skipped?**
Some country-code registries do not run an RDAP service yet. Those rows are free and say so.

**Why no owner or contact details?**
They are personal data in most cases, and most registries redact them anyway. This actor never returns them.

### Limits: what this actor does not do

- It does not scrape WHOIS text (port 43) or registrar websites, and does not use proxies or captcha solving.
- It does not return personal data: no registrant, admin, tech or abuse contact names, emails, phones or addresses.
- It does not query DNS itself (nameservers and the DNSSEC flag come from the registry record), and does not check
  websites or SSL certificates, and does not buy or reserve domains.
- Dates and fields are what the registry publishes; some registries leave fields out.

### Changelog

- 0.2 update (October 14, 2026): a redirected or mismatched RDAP answer is a free `mismatch` row; at least 1 s
  between requests to the same registry; at most 500 .com/.net domains per run.
- 0.2 (October 2026): subdomains and URLs are reduced to the registered domain; IDNA 2008 for international names;
  a server that rate limits is not queried again; new `maxDomains` input.
- 0.1 (October 2026): first version.

# Actor input Schema

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

Domain names, one per item (example.com, bücher.de). URLs and subdomains are accepted and reduced to the registered domain with the public suffix list (https://www.example.com/page and blog.example.com both look up example.com). Duplicates are looked up once.

## `delaySecs` (type: `number`):

Politeness gap per registry server (at least 1 s is always kept). Raise it if you see HTTP 429 (rate limited) rows.

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

Per-request network timeout. A whole lookup (with redirects) is capped at twice this value.

## `maxDomains` (type: `integer`):

Unique domains looked up in this run (hard maximum 10,000). Domains over the limit are not looked up and not charged; the count is in SUMMARY. .com and .net are also capped at 500 unique domains per run (Verisign's RDAP terms); extra .com/.net domains become free skipped rows. Keep lists to what you need: registries' RDAP terms of use apply.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "example.com",
    "iana.org"
  ],
  "delaySecs": 1,
  "timeoutSecs": 15,
  "maxDomains": 1000
}
```

# Actor output Schema

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

One row per domain: status codes, nameservers, DNSSEC, registrar and dates (non-personal fields only). Only found domains (status ok) are billed; not_found, error and skipped rows are free.

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

Counts of found, not found, error and skipped domains, duplicates ignored, the bootstrap source used, and why the run stopped (stopReason).

# 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.com",
        "iana.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kelp_forest_labs/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.com",
        "iana.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("kelp_forest_labs/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.com",
    "iana.org"
  ]
}' |
apify call kelp_forest_labs/rdap-domain-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kelp_forest_labs/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/uh491qPdiPZIYDnE5/builds/1ypceaOeJ3ybmQPrI/openapi.json
