# Domain WHOIS & DNS Lookup - Bulk RDAP, $2 per 1,000 (`pennydata/bulk-domain-whois-dns-lookup`) Actor

Bulk domain WHOIS lookup and DNS lookup via official RDAP: availability, registrar, created and expiry dates, age, nameservers, MX, TXT. Up to 1,000 domains per run, no proxy.

- **URL**: https://apify.com/pennydata/bulk-domain-whois-dns-lookup.md
- **Developed by:** [Jeremy Larsen](https://apify.com/pennydata) (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

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

## Domain WHOIS & DNS Lookup - Bulk RDAP, $2 per 1,000

**Bulk domain WHOIS lookup and DNS lookup**: check up to 1,000 domains per run and get availability, registrar, creation and expiry dates, age in days, status flags, nameservers and A/MX/TXT records. It uses RDAP, the official successor to WHOIS, plus DNS, so there is no scraping, no proxy and no captcha. Errors and unknown results are free.

**Free to try:** a new Apify account includes free monthly platform credit, enough to validate the output on a few dozen domains before you pay anything. This Actor has no hidden minimums: failed items are never billed.

### How to use Bulk WHOIS Domain Lookup (RDAP)

1. Paste domains (or URLs) into **domains**; duplicates are removed.
2. Click **Start**.
3. Export the dataset as JSON, CSV or Excel.
4. Re-run any `error` rows later if a registry rate-limited you.

### Pricing

Pay per event, no subscription and no compute fees on top. Price: **$2.00 per 1,000 domains**.

| Event | When it is charged | Price |
|---|---|---|
| `domain-lookup` | One domain successfully looked up via RDAP or DNS evidence. | $0.002 |

Failed, blocked or unknown items are not billed. Set a maximum cost per run in the run options to cap spend.

### Example input

```json
{
  "domains": [
    "example.com",
    "python.org",
    "some-name-nobody-registered-12345.com"
  ]
}
```

### Example output

Sample output item (abridged, from the Actor README).

```json
{
  "domain": "python.org",
  "available": false,
  "registrar": "Gandi SAS",
  "created": "1995-03-27T05:00:00.545Z",
  "expires": "2033-03-28T05:00:00Z",
  "ageDays": 11525,
  "nameservers": [
    "ns-1134.awsdns-13.org"
  ],
  "mx": [
    "50 mail.python.org"
  ],
  "source": "rdap"
}
```

### Details and limits

Give it a list of up to 1000 domains and get back, for each one: **is it available, who is the registrar, when was it created and when does it expire, how old is it (days), registry status flags, nameservers, A / MX / TXT records**. It uses RDAP, the official ICANN replacement for WHOIS, plus ordinary DNS lookups. No website is scraped, no proxy is needed, and no captcha is involved.

### What it does

- Input: `domains`, a list of domain names (maximum 1000 per run, duplicates removed). URLs are accepted and reduced to the registrable domain (`https://www.amazon.com/x` becomes `amazon.com`; a small built-in rule handles common `co.uk`-style suffixes).
- The IANA RDAP bootstrap file (`data.iana.org/rdap/dns.json`) is fetched once per run to find the registry RDAP server for each TLD.
- RDAP requests run with at most 5 in flight per registry server, with exponential backoff and `Retry-After` handling on HTTP 429 and 5xx.
- DNS (A, MX, NS, TXT) is resolved with the platform resolver.
- Output per domain: `domain`, `available`, `registrar`, `created`, `expires`, `ageDays`, `status`, `nameservers`, `a`, `mx` (as `"priority host"`), `txt`, `source` (`rdap` or `dns-only`), `checkedAt`, plus `note` or `error` when relevant.

### Limits and honesty notes

- `available: true` means the registry answered "not found" for that exact name. It is a good signal, not a purchase guarantee: reserved, premium, blocked or restricted names can still be unobtainable.
- **Some country-code TLDs have no RDAP service** (for example `.de`, `.io` and `.ac` at the time of writing). For these, `source` is `dns-only`: if the domain has NS, A or MX records it is reported `available: false` with nameservers and DNS records, but registrar, dates and age are `null`. If it has no DNS records either, `available` is `null` (unknown) and it is **not charged**. A registered domain with no DNS records can therefore show as unknown.
- Registry servers may rate limit. After retries a persistent failure is returned as an `error` row and not charged; re-run those domains later.
- Some registries (notably country-code ones) omit dates or show a generic registrar name. Fields that the registry does not provide are `null`.
- **Privacy:** only registry-level facts are output. RDAP registrant, admin and tech contact entities (names, emails, phones) are never read or stored, and many registries redact them anyway.
- The registrable-domain reduction is a heuristic, not the full public suffix list; for unusual multi-level suffixes pass the exact registrable domain.

### More from PennyData

- [Website Screenshot & URL to PDF](https://apify.com/pennydata/shot-pdf): Full-page screenshots and URL/HTML to PDF with headless Chromium.
- [Bulk Email Validator (No SMTP)](https://apify.com/pennydata/bulk-email-validator-no-smtp): Syntax, MX, disposable, role and typo checks for email lists.
- [App Store Reviews Scraper](https://apify.com/pennydata/appstore-reviews-rss): Apple app reviews by app ID and country from the public RSS feed.
- [Website Tech Stack Detector](https://apify.com/pennydata/website-tech-stack-detector): CMS, ecommerce, analytics, CDN and JS frameworks per URL.

### FAQ

**Why is a ccTLD result `dns-only`?**\
Some country-code TLDs (e.g. .de, .io) have no RDAP service. The Actor then reports DNS evidence only and says so; unknown results are not charged.

**Is it legal? Does it expose personal data?**\
Only registry-level facts are output. Registrant, admin and tech contact entities are never read or stored.

**Need a custom field, a higher volume or a different source?**\
Open an issue on the Actor page and describe what you need; custom variants are possible.

**Is it maintained?**\
Yes. Reports of breakage are answered through the Issues tab, and runs that fail are not billed.

Built with AI assistance (Claude); maintained by the publisher.

# Actor input Schema

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

Domain names such as example.com. URLs are accepted and reduced to the host name. Maximum 1000 per run; duplicates are removed.

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

Total number of domains looked up in parallel. At most 5 requests are ever in flight to any single RDAP server regardless of this value.

## Actor input object example

```json
{
  "domains": [
    "example.com",
    "apify.com"
  ],
  "maxConcurrency": 20
}
```

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

// Run the Actor and wait for it to finish
const run = await client.actor("pennydata/bulk-domain-whois-dns-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": [
        "example.com",
        "apify.com",
    ] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,pennydata/bulk-domain-whois-dns-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/pYjzn2yloiQMdSPAJ/builds/tWKSuaVicq8Ui575o/openapi.json
