# Bulk RDAP Domain Lookup: Expiry, Registrar, DNSSEC (`obligate_castle/bulk-rdap-domain-lookup`) Actor

Look up hundreds of domains in a single run and get one normalized record per domain: registration and expiry dates, days until expiry, registrar, EPP status codes (locks, hold, redemption), nameservers, DNSSEC and availability.

- **URL**: https://apify.com/obligate\_castle/bulk-rdap-domain-lookup.md
- **Developed by:** [Yoann TUQUET](https://apify.com/obligate_castle) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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.

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 RDAP Domain Lookup – Expiry, Registrar, Status, Nameservers & DNSSEC

Look up hundreds of domains in a single run and get **one normalized record per domain**: **registration and expiry dates**, **days until expiry**, **registrar**, **EPP status codes** (locks, hold, redemption), **nameservers**, **DNSSEC** and **availability**.

Data comes straight from the official **RDAP** registries (the successor of WHOIS), discovered through the **IANA RDAP bootstrap**. No scraping, no third-party API, no login, no personal data: registrant, admin and technical contacts are deliberately never read or returned.

### Why use it

- ✅ **Structured and consistent**: the same fields for .com, .org, .dev, .co.uk and every other TLD with an RDAP server, instead of free-text WHOIS output that differs by registry.
- ✅ **Built for lists**: paste 10 or 10,000 domains or URLs. Duplicates are removed and invalid entries are skipped and never billed.
- ✅ **Alerts included**: expiring soon, expired, on hold, in redemption, pending delete, no transfer lock, no DNSSEC.
- ✅ **Privacy by design**: no personal data. Only the registrar (a company) and technical data are returned.
- ✅ **Polite**: at most 2 requests per second to any given RDAP server.
- ✅ **Pay only for answers**: one charge per conclusive lookup. Errors and TLDs without RDAP are free.

### Use cases

1. **Domain portfolio monitoring**: schedule a weekly run on the domains you own and get alerted before one expires or is put on hold.
2. **Brand protection and due diligence**: check the age, registrar and nameservers of look-alike domains or of a supplier's domains.
3. **Availability screening**: test a list of candidate names and keep the ones the registry reports as not registered.
4. **Security and IT inventories**: verify transfer locks and DNSSEC across all your domains, and spot changes in nameservers between runs.
5. **Lead and market analysis**: measure domain age and registrar market share for a list of companies (no contact data involved).

### How to use it

1. Click **Try for free** and paste your domains (or full URLs) into **Domains**.
2. Optionally set the **expiry warning threshold** (30 days by default).
3. Click **Start**. When the run finishes, export the results as **JSON, CSV, Excel or HTML**, or fetch them through the Apify API.

Tip: create a **Schedule** to re-run the lookup weekly and trigger a webhook or an integration when `alerts` is not empty.

### What is returned

| Field | Details |
|---|---|
| `outcome` | `registered`, `not_registered`, `unsupported_tld` or `error` |
| `registered` | `true` / `false`, `null` if inconclusive |
| `registrar`, `registrarIanaId` | Registrar name and IANA identifier |
| `createdAt`, `updatedAt`, `expiresAt` | ISO 8601 dates |
| `daysUntilExpiry`, `domainAgeDays` | Computed at run time (negative when expired) |
| `eppStatuses` | For example `client transfer prohibited`, `redemption period`, `client hold` |
| `nameservers` | Lowercase, sorted |
| `dnssecSigned` | Whether the delegation is signed |
| `alerts` | Human-readable warnings |
| `rdapServer` | The registry server that answered |

### Input

```json
{
  "items": ["example.com", "https://www.github.com/", "wikipedia.org", "this-domain-is-surely-free-4821.com"],
  "expiryWarningDays": 30,
  "timeoutSecs": 15
}
```

| Field | Description | Default |
|---|---|---|
| `items` | Domains or URLs (only the domain name is used, a leading `www.` is removed, internationalized names are converted to punycode) | required |
| `expiryWarningDays` | Add an alert when a domain expires within this many days | `30` |
| `timeoutSecs` | Network timeout per RDAP request | `15` |

Enter registered domain names (`example.com`, `bbc.co.uk`), not subdomains other than `www`.

### Output

One dataset item per domain. A registered domain:

```json
{
  "target": "https://www.example.com/",
  "domain": "example.com",
  "tld": "com",
  "checkedAt": "2026-09-18T16:40:51.974Z",
  "outcome": "registered",
  "registered": true,
  "registrar": "RESERVED-Internet Assigned Numbers Authority",
  "registrarIanaId": "376",
  "createdAt": "1995-08-14T04:00:00.000Z",
  "updatedAt": "2026-08-14T08:01:43.000Z",
  "expiresAt": "2027-08-13T04:00:00.000Z",
  "daysUntilExpiry": 328,
  "domainAgeDays": 11358,
  "eppStatuses": ["client delete prohibited", "client transfer prohibited", "client update prohibited"],
  "nameservers": ["elliott.ns.cloudflare.com", "hera.ns.cloudflare.com"],
  "dnssecSigned": true,
  "alerts": [],
  "rdapServer": "https://rdap.verisign.com/com/v1/",
  "error": null
}
```

A domain the registry does not know:

```json
{
  "target": "this-domain-is-surely-free-4821.com",
  "domain": "this-domain-is-surely-free-4821.com",
  "tld": "com",
  "checkedAt": "2026-09-18T16:40:51.975Z",
  "outcome": "not_registered",
  "registered": false,
  "registrar": null,
  "expiresAt": null,
  "eppStatuses": [],
  "nameservers": [],
  "alerts": [],
  "rdapServer": "https://rdap.verisign.com/com/v1/",
  "error": null
}
```

### Pricing

Pay per event: **$0.003 per domain looked up**, which is **$3 per 1,000 domains**. Lookups with `outcome` `error` or `unsupported_tld`, as well as invalid and duplicate entries, are not charged. You can cap your spending with the maximum charge setting of each run.

### Integrations

- **API**: start runs and download results from any language with the Apify API or clients.
- **Schedules and webhooks**: monitor expiry dates periodically and trigger a webhook when it finishes.
- **Make, Zapier, n8n**: send alerts to Slack, email or Google Sheets.
- **AI agents**: callable as a tool through the Apify MCP server.

### FAQ

**Is this WHOIS?**
It is RDAP, the JSON protocol that replaces WHOIS. It is served by the registries themselves, so the data is authoritative and consistently structured.

**Why is there no owner name, email or phone?**
The Actor never reads registrant, admin or technical contacts. Those are personal data and are often redacted by the registries anyway.

**What does `not_registered` mean exactly?**
The authoritative registry answered "not found". In most cases the name is available, but a registry can also reserve or block names, so confirm with a registrar before buying.

**Why is my TLD `unsupported_tld`?**
Some registries do not publish an RDAP server in the IANA bootstrap (for example .de and .io at the time of writing). Those lookups are free.

**Some fields are `null`.**
Registries decide what they publish. A missing field is `null` instead of being guessed.

**How fast is it?**
Requests to a same RDAP server are spaced by 500 ms, so a list of 1,000 .com domains takes roughly 8 to 10 minutes.

### Limitations

- Only TLDs listed in the IANA RDAP bootstrap are supported.
- Subdomains are not resolved to their registered domain: pass the registered name (`example.co.uk`, not `blog.example.co.uk`).
- Registries apply their own rate limits; the Actor retries a few times on HTTP 429 or 503, then reports `error` (not billed).
- Dates and statuses are the registry's own; some registries omit the creation date, expiry date or DNSSEC data.

# Actor input Schema

## `items` (type: `array`):

Domains to look up (e.g. example.com). URLs are accepted, only the domain name is used. Internationalized names are converted to punycode. One result is billed per conclusive lookup.

## `expiryWarningDays` (type: `integer`):

Add an alert when a domain expires within this many days.

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

Network timeout applied to each RDAP request.

## Actor input object example

```json
{
  "items": [
    "example.com",
    "github.com",
    "openai.com",
    "this-domain-is-surely-free-4821.com"
  ],
  "expiryWarningDays": 30,
  "timeoutSecs": 15
}
```

# Actor output Schema

## `overview` (type: `string`):

Registrar, dates, days until expiry, DNSSEC, statuses and alerts for each domain.

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

Complete record per domain, including registrar IANA ID, nameservers and RDAP server.

# 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 = {
    "items": [
        "example.com",
        "github.com",
        "openai.com",
        "this-domain-is-surely-free-4821.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("obligate_castle/bulk-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 = { "items": [
        "example.com",
        "github.com",
        "openai.com",
        "this-domain-is-surely-free-4821.com",
    ] }

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

```

## MCP server setup

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