# Bulk WHOIS Lookup API: Domain Expiry, Registrar & DNS (RDAP) (`saadhazz/domain-whois-rdap`) Actor

Bulk WHOIS lookup through official RDAP: registration and expiration dates, domain age, registrar, status codes, nameservers, DNSSEC, availability, plus DNS, MX, SPF and DMARC records. No personal data. $1 per 1,000 domains.

- **URL**: https://apify.com/saadhazz/domain-whois-rdap.md
- **Developed by:** [saad hazz](https://apify.com/saadhazz) (community)
- **Categories:** Developer tools, SEO tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

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

**Run bulk WHOIS lookups on thousands of domains and get clean JSON in return:** registration date, expiration date, domain age, days until expiry, registrar and IANA ID, EPP status codes, nameservers, DNSSEC, and availability. Optionally add **DNS records, MX, SPF and DMARC policy** in the same run. Lookups go through **RDAP**, the official ICANN successor to WHOIS, so you get structured data instead of fragile text parsing. The price is **$1 per 1,000 domains**, with DNS included.

### What you can use it for

- **Domain portfolio management.** Track expiry dates and get alerts before domains lapse (`daysUntilExpiry`).
- **Lead qualification and enrichment.** Domain age, registrar, whether a domain has email (MX), and how mature its email security is (SPF/DMARC).
- **Security and fraud checks.** Flag newly registered domains (`domainAgeDays` < 30), missing DMARC, or suspicious status codes.
- **Brand protection.** Check your brand across dozens of TLDs and see which are registered and which are `likely_available`.
- **Domain investing.** Bulk availability and drop-date research.

### Why this WHOIS API?

- **Official sources.** It uses the IANA RDAP bootstrap and each registry's RDAP server, covering all gTLDs (.com, .net, .org, .io, .ai, .app, .dev, ...) and a growing list of ccTLDs (.uk, .de, .fr, .nl, .ch, .ca, .au, .co, .me, .tv, ...). No scraping of WHOIS websites.
- **Accepts messy input.** URLs, subdomains and email addresses are reduced to the registrable domain with the Public Suffix List (`https://www.bbc.co.uk/news` becomes `bbc.co.uk`). Unicode (IDN) domains are supported and duplicates are removed.
- **Clean, typed output.** Dates are ISO 8601 UTC, ages are computed for you, nameservers are lower-cased, and status codes come as an array.
- **Rate-limit aware.** Concurrency is capped per registry, `Retry-After` is honoured, and backoff includes jitter. In our test, 250 domains across 13 TLDs finished in about 30 seconds.
- **Fair billing.** Invalid inputs and lookups that fail completely are **free** and listed in the `INVALID_DOMAINS` / `FAILED_DOMAINS` records.
- **Privacy by design.** No personal data is collected: no registrant names, emails, phone numbers or street addresses. We return only the registrant **organization and country** when the registry publishes them, and drop redacted or privacy-proxy values.

### Input

| Field | Description |
|---|---|
| `domains` | Domains, URLs or emails. One per line. |
| `includeDns` | Adds A/AAAA/MX/NS/TXT records, `spfRecord`, `dmarcRecord` and `dmarcPolicy` (default on). |
| `followRegistrarRdap` | For .com/.net, also asks the registrar's RDAP server for the registrant organization and country. Costs one extra request per domain and is off by default. |
| `maxDomains` | Safety cap. |
| `maxConcurrency`, `perRegistryConcurrency` | Advanced speed controls. |

### Output example

```json
{
  "domain": "wikipedia.org",
  "domainUnicode": "wikipedia.org",
  "tld": "org",
  "availability": "registered",
  "registered": true,
  "rdapSupported": true,
  "rdapServer": "https://rdap.publicinterestregistry.org/rdap/",
  "handle": null,
  "statuses": [
    "client delete prohibited",
    "client transfer prohibited",
    "client update prohibited"
  ],
  "registrationDate": "2001-01-13T00:12:14Z",
  "expirationDate": "2027-01-13T00:12:14Z",
  "lastChangedDate": "2026-08-12T08:47:19Z",
  "domainAgeDays": 9397,
  "daysUntilExpiry": 98,
  "registrarName": "MarkMonitor Inc.",
  "registrarIanaId": "292",
  "registrantOrganization": "Wikimedia Foundation, Inc.",
  "registrantCountry": "US",
  "nameservers": [
    "ns0.wikimedia.org",
    "ns1.wikimedia.org",
    "ns2.wikimedia.org"
  ],
  "dnssec": false,
  "checkedAt": "2026-10-06T17:39:04Z",
  "dnsA": [
    "208.80.154.224"
  ],
  "dnsAAAA": [
    "2620:0:861:ed1a::1"
  ],
  "dnsMX": [
    "10 mx-in1001.wikimedia.org",
    "10 mx-in2001.wikimedia.org"
  ],
  "dnsNS": [
    "ns0.wikimedia.org",
    "ns1.wikimedia.org",
    "ns2.wikimedia.org"
  ],
  "dnsTXT": [
    "yandex-verification: 35c08d23099dc863",
    "v=spf1 include:_cidrs.wikimedia.org ~all",
    "google-site-verification=AMHkgs-4ViEvIJf5znZle-BSE2EPNFqM1nDJGRyn2qk"
  ],
  "hasMx": true,
  "spfRecord": "v=spf1 include:_cidrs.wikimedia.org ~all",
  "dmarcRecord": "v=DMARC1; p=reject; rua=mailto:dmarc-rua@wikimedia.org;",
  "dmarcPolicy": "reject"
}
```

`availability` is `registered`, `likely_available` (the registry has no record; premium or reserved names can still apply) or `unknown`. For TLDs without a public RDAP service (for example .sa), we fall back to DNS delegation, set `rdapSupported: false` and leave registry dates empty. Some registries (such as .de and .nl) do not publish registration or expiry dates by policy, so those fields are `null`.

### Pricing

Pricing is pay-per-event: **$0.001 per domain checked ($1 per 1,000)**, with DNS and email-security records included at no extra cost. Many alternatives charge $2.50 to $20 per 1,000 lookups or add a per-run start fee. Set *Max total charge* in the run options to cap spending; the run stops cleanly at your limit.

### Integrations

Schedule a daily or weekly run over your portfolio, then send rows with `daysUntilExpiry < 30` to Slack, email or Google Sheets using Apify integrations. You can also call the Actor synchronously from your own app through the Apify API.

### Run it from code: API, Python, JavaScript or cURL

Every Apify Actor is also a REST API. Get your token in Apify Console under **Settings → API & Integrations**, then:

**cURL** (runs the Actor and returns the WHOIS records in one call):

```bash
curl -X POST "https://api.apify.com/v2/acts/saadhazz~domain-whois-rdap/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domains": ["apify.com", "example.org"], "includeDns": true}'
```

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("saadhazz/domain-whois-rdap").call(run_input={"domains": ["apify.com", "example.org"], "includeDns": true})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

**JavaScript / Node.js** (`npm i apify-client`):

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('saadhazz/domain-whois-rdap').call({"domains": ["apify.com", "example.org"], "includeDns": true});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Use it with AI agents (MCP), Make, Zapier, n8n and Google Sheets

- **AI agents and LLM apps:** connect Claude, Cursor, ChatGPT or any MCP client to `https://mcp.apify.com/?tools=saadhazz/domain-whois-rdap` and the agent can call this Actor as a tool.
- **No-code:** use the official Apify integrations for Make, Zapier and n8n, or export the dataset straight to Google Sheets, CSV, Excel or JSON.
- **Scheduling and webhooks:** create a Schedule in Apify Console (e.g. every morning) and add a webhook or Slack/email integration to get notified when new data is ready.

### Is WHOIS/RDAP lookup legal?

Yes. RDAP is the IETF-standard protocol (RFC 9082/9083) that ICANN requires gTLD registries and registrars to operate as a public service. DNS data is fetched through Cloudflare's public DNS-over-HTTPS resolver. This Actor does not collect personal data. Please follow each registry's acceptable-use policy: don't use the results for spam or unsolicited marketing.

### FAQ

**Why is the expiration date empty for some domains?** That registry doesn't publish it (for example .de or .nl), or the TLD has no RDAP service. Check `rdapSupported`.

**Is `likely_available` guaranteed?** No. It means the registry has no record of the domain. Check with a registrar before you rely on it, because reserved and premium names exist.

**How many domains can I check?** Tens of thousands per run. Throughput depends on each registry's rate limits.

**Do you support raw WHOIS (port 43)?** Not yet. A WHOIS fallback for ccTLDs without RDAP is on the roadmap.

**How do I check the expiry date of many domains at once?** Paste the list (one per line, or upload via API) into **Domains** and run. Each row has `expirationDate` and `daysUntilExpiry`; sort by it or schedule a weekly run to catch domains about to expire.

**What is the difference between WHOIS and RDAP?** RDAP is the modern, official replacement for port-43 WHOIS, run by the same registries and returning structured JSON. ICANN made RDAP the authoritative source for gTLDs, so it is more reliable to parse than WHOIS text.

### More data APIs from the same developer

- [Job Search API: Career Site Jobs](https://apify.com/saadhazz/career-site-job-search): search 400k+ jobs from 13,000+ company career sites (Greenhouse, Lever, Ashby, Workable…) by title, country and remote, with new-job alerts. $2 / 1,000 jobs.
- [ATS Jobs API](https://apify.com/saadhazz/ats-jobs-api): every open job from a list of companies on Greenhouse, Lever, Ashby, SmartRecruiters or Recruitee, in one schema. $1 / 1,000 jobs.
- [Remote Jobs API](https://apify.com/saadhazz/remote-jobs-aggregator): remote and work-from-home jobs from Remote OK, Himalayas, Jobicy and Arbeitnow, deduplicated. $1 / 1,000 jobs.
- [Sitemap URL Extractor](https://apify.com/saadhazz/sitemap-url-extractor): every URL a website lists in its XML sitemaps, with lastmod, hreflang and optional HTTP status. $0.40 / 1,000 URLs.
- [PDF Text Extractor](https://apify.com/saadhazz/pdf-text-extractor): PDF URLs to clean page-by-page text, Markdown tables and metadata for RAG/LLM pipelines.
- [SEC EDGAR Filings Monitor](https://apify.com/saadhazz/sec-filings-monitor): new 8-K, 10-Q, 10-K and Form 4 filings for a list of tickers from the official SEC API.

Found a bug or need a field? Open an issue on the Issues tab; Issues are checked daily.

# Actor input Schema

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

Domains, URLs or email addresses (we extract the registrable domain: https://www.bbc.co.uk/news -> bbc.co.uk). Duplicates are removed. Unicode domains are supported.

## `includeDns` (type: `boolean`):

Adds A, AAAA, MX, NS, TXT records, SPF and DMARC (with policy) via DNS-over-HTTPS.

## `followRegistrarRdap` (type: `boolean`):

For thin registries (.com/.net) the registrant organization and country live at the registrar. One extra request per domain. Personal data is never collected; redacted/privacy-proxy values are dropped.

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

Safety cap on the number of unique domains processed in one run.

## `maxConcurrency` (type: `integer`):

How many lookups/downloads run in parallel.

## `perRegistryConcurrency` (type: `integer`):

Keeps us well inside registry rate limits (we also honour Retry-After).

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "example.org",
    "github.io"
  ],
  "includeDns": true,
  "followRegistrarRdap": false,
  "maxDomains": 10000,
  "maxConcurrency": 20,
  "perRegistryConcurrency": 4
}
```

# Actor output Schema

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

One domain per item: RDAP registration data, availability and optional DNS/email-security records.

## `runStats` (type: `string`):

Counters for results, HTTP outcomes and errors in this run.

## `allRecords` (type: `string`):

Every auxiliary record written by the run (reports, invalid/failed inputs, large text files).

# 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",
        "github.io"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("saadhazz/domain-whois-rdap").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",
        "github.io",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("saadhazz/domain-whois-rdap").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",
    "github.io"
  ]
}' |
apify call saadhazz/domain-whois-rdap --silent --output-dataset

```

## MCP server setup

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

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/pFRzjhRyedh5ybTuH/builds/oCOCJtC6fatpgEbHP/openapi.json
