# WHOIS Domain Lookup — RDAP, DNS & expiry, $0.50 per 1,000 (`theaisololab/whois-domain-lookup`) Actor

Bulk WHOIS/RDAP lookup: registrar, creation and expiry dates, availability, nameservers, plus DNS, email provider and DMARC. $0.50 per 1,000 domains; failed lookups are free.

- **URL**: https://apify.com/theaisololab/whois-domain-lookup.md
- **Developed by:** [AI Solo Lab](https://apify.com/theaisololab) (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

from $0.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

## WHOIS Domain Lookup — RDAP, DNS & expiry, $0.50 per 1,000

Check thousands of domains at once: registered or available, registrar, creation and expiry dates, status codes and nameservers — straight from each registry's official **RDAP** server, with **WHOIS** as a fallback. Every row also carries the domain's **DNS**: which company hosts its DNS, which email provider it uses, its SPF and DMARC policy, and which SaaS tools have verified it.

- **$0.50 per 1,000 domains.** Domains the registry doesn't answer for, and invalid lines, are free.
- **RDAP first, WHOIS fallback** for .io, .de, .it and other extensions without RDAP.
- **DNS, email provider, DMARC and verified SaaS tools in the same row** — no second tool needed.
- **No personal data:** registrant contacts are never collected, and raw WHOIS text is never stored.
- **No login, no proxy, no API key.**

### What people use it for

- **Expiring-domain watchlists** — sort by `daysToExpiry` to see which of your (or your clients') domains need renewing.
- **Lead enrichment** — see which email provider (Google Workspace, Microsoft 365...) and DNS host a company uses, and which SaaS tools it has verified.
- **Security and brand protection** — check lookalike domains, their age, registrar, DNSSEC and DMARC policy.
- **Domain investing** — check availability and age of long lists of names.
- **AI agents** — call it from Claude, Cursor or any MCP client through the [Apify MCP server](https://mcp.apify.com); every row has a one-sentence `summary` written for LLMs.

### Input

```json
{
  "domains": ["stripe.com", "https://www.bbc.co.uk/news", "github.io", "zz-not-registered-theaisololab-9281.com"],
  "includeDns": true,
  "whoisFallback": true
}
```

| Field | What it does | Default |
|---|---|---|
| `domains` | Domains or URLs. Subdomains are reduced to the registrable domain (`www.bbc.co.uk` → `bbc.co.uk`). Duplicates are removed. Up to 100,000 per run. | — |
| `includeDns` | Also look up A, AAAA, MX, NS, SPF and DMARC, and name the email and DNS providers. Included in the price. | on |
| `whoisFallback` | For extensions without RDAP, ask the registry's WHOIS server instead. | on |
| `maxConcurrency` | Domains checked in parallel. Registries are always queried politely. | 10 |
| `requestTimeoutSecs` | Timeout of each RDAP request. | 15 |

### Output

One row per domain (a real row; `mxRecords` shortened):

```json
{
  "input": "stripe.com",
  "domain": "stripe.com",
  "tld": "com",
  "registered": true,
  "available": false,
  "registrar": "SafeNames Ltd.",
  "registrarIanaId": "447",
  "createdDate": "1995-09-12",
  "updatedDate": "2025-10-01",
  "expiresDate": "2027-09-11",
  "ageDays": 11339,
  "daysToExpiry": 348,
  "status": ["client delete prohibited", "client transfer prohibited", "client update prohibited",
             "server delete prohibited", "server transfer prohibited", "server update prohibited"],
  "nameservers": ["ns-1087.awsdns-07.org", "ns-1882.awsdns-43.co.uk", "ns-423.awsdns-52.com", "ns-705.awsdns-24.net"],
  "dnssec": false,
  "source": "rdap",
  "lookupServer": "rdap.verisign.com",
  "aRecords": ["198.137.150.231", "198.202.176.231"],
  "aaaaRecords": [],
  "mxRecords": [{"priority": 10, "host": "aspmx.l.google.com"}, {"priority": 20, "host": "alt1.aspmx.l.google.com"}],
  "nsRecords": ["ns-1087.awsdns-07.org", "ns-1882.awsdns-43.co.uk", "ns-423.awsdns-52.com", "ns-705.awsdns-24.net"],
  "spf": "v=spf1 ip4:198.2.180.60/32 ip4:13.111.2.227/32 include:spf1.stripe.com include:greenhouse-outbound-mail.stripe.com include:_spf.qualtrics.com ~all",
  "dmarcPolicy": "reject",
  "emailProvider": "Google Workspace",
  "dnsProvider": "AWS Route 53",
  "verifications": ["Anthropic", "Apple", "Atlassian", "Canva", "DocuSign", "Google", "LiveRamp", "Meta",
                    "Microsoft 365", "OpenAI", "Postman", "Stripe"],
  "summary": "stripe.com: registered 1995-09-12 with SafeNames Ltd., expires 2027-09-11 (in 348 days); DNS by AWS Route 53; email by Google Workspace; DMARC reject.",
  "ok": true,
  "error": null,
  "checkedAt": "2026-09-28T13:38:00+00:00"
}
```

`registered` is `true`, `false` (then `available` is `true`) or `null` when the registry gave no answer — those rows have `ok: false`, the reason in `error`, and are not charged. `nameservers` come from the registry; `nsRecords` from live DNS (they can differ). `source` says whether the answer came from RDAP or WHOIS, and `lookupServer` which server gave it. `verifications` lists only provider names found in TXT records — never the records themselves. DNS fields are empty when the domain isn't registered or `includeDns` is off.

### How it works

The Actor reads IANA's RDAP bootstrap file to find each extension's official registry server, and asks it about each domain (HTTP 404 means not registered). Extensions without RDAP are asked over WHOIS (port 43), at most 2 connections per registry server and one query per second, because those servers ban aggressive clients. DNS comes from Google Public DNS over HTTPS, with Cloudflare as a fallback.

**Limits, stated plainly:**

- Some registries publish no dates at all: `.de` only says whether a domain is registered. Those rows are still definite answers (and charged).
- The `.es` registry has no public WHOIS, and the `.pt` registry's WHOIS server doesn't accept connections from Apify's servers, so `.es` and `.pt` domains come back free with an error. Other extensions with no reachable RDAP or WHOIS behave the same way; when a WHOIS server stops answering, the rest of its domains fail at once (free) instead of waiting.
- "Available" means "likely available": premium and reserved names can look unregistered.
- Large lists of WHOIS-only extensions (.io, .de...) are slower — about one domain per second per registry — to stay within their limits. RDAP extensions (.com, .net, .org, .uk, .fr and 1,200 more) are much faster.
- Registrant names, emails, phones and addresses are never returned, even when a registry publishes them.

### Pricing

Pay per event: **$0.50 per 1,000 domains** ($0.0005 per domain with a definite answer, registered or not). Domains the registry doesn't answer for and invalid inputs are never charged. You can cap spending per run in the run options — the Actor stops cleanly when it's reached.

### FAQ

**Is this legal?** Yes. RDAP, WHOIS and DNS are public services run by registries and DNS operators for exactly this. No login, and no personal data is collected.

**Why RDAP and not WHOIS?** RDAP is the official, structured successor of WHOIS: clean JSON, real dates, no scraping of free text. WHOIS is used only where a registry doesn't offer RDAP yet.

**Why is a domain's registrar or date empty?** The registry didn't publish it (e.g. `.de` publishes no dates). The row says so in its summary.

**Can I check subdomains?** You can paste them; they are reduced to the registrable domain, because that's what a registry holds.

### More tools from theaisololab

- [Tech Stack Detector](https://apify.com/theaisololab/tech-stack-detector) — technologies behind any website, $0.01 per domain.
- [Google Ads Transparency Scraper](https://apify.com/theaisololab/google-ads-transparency) — every Google ad a company runs.

### Changelog

- **0.1** — first release.

This Actor is independent and not affiliated with IANA or any registry.

# Actor input Schema

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

Domains (example.com) or URLs. Subdomains are reduced to the registrable domain. Duplicates are removed. Up to 100,000 per run.

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

Also look up A, AAAA, MX, NS, SPF and DMARC, and name the email and DNS providers. Included in the price.

## `whoisFallback` (type: `boolean`):

For extensions without RDAP (.io, .co, .de, .it...), ask the registry's WHOIS server instead.

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

How many domains to check in parallel. Registries are always queried politely, whatever this value.

## `requestTimeoutSecs` (type: `integer`):

Timeout of each RDAP request, for example 15. Slow registries are retried a few times before the domain is given up (for free).

## Actor input object example

```json
{
  "domains": [
    "stripe.com",
    "apify.com",
    "zz-not-registered-theaisololab-9281.com"
  ],
  "includeDns": true,
  "whoisFallback": true,
  "maxConcurrency": 10,
  "requestTimeoutSecs": 15
}
```

# Actor output Schema

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

One row per domain: registered or available, registrar, created and expiry dates, nameservers, DNS, email and DNS provider, DMARC policy and a one-sentence summary.

# 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": [
        "stripe.com",
        "apify.com",
        "zz-not-registered-theaisololab-9281.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("theaisololab/whois-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": [
        "stripe.com",
        "apify.com",
        "zz-not-registered-theaisololab-9281.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("theaisololab/whois-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": [
    "stripe.com",
    "apify.com",
    "zz-not-registered-theaisololab-9281.com"
  ]
}' |
apify call theaisololab/whois-domain-lookup --silent --output-dataset

```

## MCP server setup

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