# Bulk Domain WHOIS/RDAP, DNS & Email Security Checker (`sysco32/domain-rdap-dns-lookup`) Actor

Bulk domain lookup via official RDAP (ICANN's WHOIS successor) with WHOIS fallback: availability, registrar, creation and expiry dates, status, nameservers, DNS records plus SPF, DMARC, MTA-STS and mail-provider checks. Change monitor.

- **URL**: https://apify.com/sysco32/domain-rdap-dns-lookup.md
- **Developed by:** [Gabor Sziladi](https://apify.com/sysco32) (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 $1.00 / 1,000 domain 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 Domain WHOIS / RDAP Lookup, DNS & Email Security Checker

Look up **thousands of domains at once**. For each one you get availability, registrar, creation, update and **expiry dates**, EPP status, nameservers and DNSSEC, all from the registry's official **RDAP** service (ICANN's modern replacement for WHOIS), with a port-43 **WHOIS fallback** for ccTLDs that don't offer RDAP yet. Add **DNS records** and an **email security audit** (mail provider, SPF, DMARC, DKIM, MTA-STS, TLS-RPT, BIMI, with a 0–100 score and a list of issues). **$1 per 1,000 domains.**

- ✅ **Availability check** for name ideas: `available: true` when the registry has no registration
- ✅ Registrar, IANA ID, abuse contact, `created_at`, `expires_at`, `days_to_expiry`, `domain_age_days`
- ✅ 1,200+ TLDs via the IANA RDAP bootstrap, plus .de, .io, .ch, .me and WHOIS for .eu, .it, .co, .jp, .at, .be, .se, .dk…
- ✅ DNS over HTTPS: A, AAAA, MX, NS, TXT, CNAME, CAA, SOA
- ✅ **Mail provider detection**: Google Workspace, Microsoft 365, Proofpoint, Mimecast, Zoho, Fastmail and 30 more
- ✅ **SPF / DMARC / DKIM audit** with plain-English issues ("DMARC policy is p=none", "SPF ends with +all")
- ✅ **Change monitor**: output only domains whose registrar, expiry, status, nameservers, MX, SPF or DMARC changed
- ✅ Filters: only available domains, only domains expiring within N days
- ✅ Paste URLs, `www.` hosts, subdomains or IDNs, and they're cleaned up automatically. One bad domain never fails the run.

### Input example

```json
{
  "domains": [
    "github.com",
    "apify.com",
    "bbc.co.uk",
    "spiegel.de",
    "my-startup-idea.io"
  ],
  "lookupRegistration": true,
  "whoisFallback": true,
  "dnsRecordTypes": [
    "A",
    "AAAA",
    "MX",
    "NS",
    "TXT"
  ],
  "emailSecurity": true,
  "onlyAvailable": false,
  "expiringWithinDays": 0,
  "onlyChanged": false
}
```

### Output example (real run)

A registered domain (long lists shortened):

```json
{
  "domain": "github.com",
  "input": "github.com",
  "host": null,
  "tld": "com",
  "registered": true,
  "available": false,
  "lookup_source": "rdap",
  "registry_server": "https://rdap.verisign.com/com/v1/",
  "registrar": "MarkMonitor Inc.",
  "registrar_iana_id": "292",
  "registrar_abuse_email": "abusecomplaints@markmonitor.com",
  "created_at": "2007-10-09T18:20:50Z",
  "updated_at": "2026-09-07T09:22:52Z",
  "expires_at": "2028-10-09T18:20:50Z",
  "days_to_expiry": 718,
  "domain_age_days": 6953,
  "status": [
    "client delete prohibited",
    "client transfer prohibited",
    "client update prohibited"
  ],
  "nameservers": [
    "dns1.p08.nsone.net",
    "dns2.p08.nsone.net",
    "dns3.p08.nsone.net",
    "…"
  ],
  "dnssec": false,
  "registrant_org": null,
  "registrant_country": null,
  "dns": {
    "A": [
      "140.82.114.3"
    ],
    "AAAA": [],
    "MX": [
      "0 github-com.mail.protection.outlook.com"
    ],
    "NS": [
      "dns1.p08.nsone.net",
      "dns2.p08.nsone.net",
      "dns3.p08.nsone.net",
      "dns4.p08.nsone.net",
      "ns-1283.awsdns-32.org",
      "ns-1707.awsdns-21.co.uk",
      "ns-421.awsdns-52.com",
      "ns-520.awsdns-01.net"
    ],
    "TXT": [
      "00Dd0000000hHE0=1TBKg000000TN2r",
      "MS=6BF03E6AF5CB689E315FB6199603BABF2C88D805",
      "MS=ms44452932",
      "…"
    ]
  },
  "has_website_ip": true,
  "mx_hosts": [
    "github-com.mail.protection.outlook.com"
  ],
  "mail_provider": "Microsoft 365",
  "email_security": {
    "spf": {
      "present": true,
      "record": "v=spf1 ip4:192.30.252.0/22 include:spf.protection.outlook.com include:_netblocks.google.com include:_netblocks2.google.com include:mail.zendesk.com include:_spf.salesforce.com include:servers.mcsv.net include:mktomail.com include:sendgrid.net ip4:62.253.227.114 ip4:166.78.69.169 ip4:166.78.69.170 ip4:166.78.71.131 ~all",
      "all": "softfail",
      "includes": [
        "spf.protection.outlook.com",
        "_netblocks.google.com",
        "_netblocks2.google.com",
        "…"
      ],
      "dns_lookups": 8,
      "multiple_records": false
    },
    "dmarc": {
      "present": true,
      "record": "v=DMARC1; p=quarantine; sp=reject; pct=100; rua=mailto:dmarc@github.com; ruf=mailto:dmarc@github.com; fo=1",
      "policy": "quarantine",
      "subdomain_policy": "reject",
      "pct": 100,
      "rua": [
        "mailto:dmarc@github.com"
      ],
      "ruf": [
        "mailto:dmarc@github.com"
      ]
    },
    "dkim_selectors_found": [
      "google",
      "selector1",
      "k1",
      "s1",
      "s2"
    ],
    "mta_sts": null,
    "tls_rpt": null,
    "bimi": null,
    "score": 90,
    "issues": []
  },
  "scraped_at": "2026-10-21T19:03:26Z"
}
```

An unregistered domain:

```json
{
  "domain": "thisdomainisprobablyfree-1729.com",
  "registered": false,
  "available": true,
  "availability_note": "No registration found in the registry. It may still be reserved, premium-priced or blocked by the registry.",
  "lookup_source": "rdap",
  "registry_server": "https://rdap.verisign.com/com/v1/"
}
```

Use the **Domains** and **Email security** dataset views, or export CSV or Excel. The `OUTPUT` record holds counts (registered, unregistered, filtered, unchanged), the WHOIS servers used and the inputs that failed or were invalid.

### Pricing

Pay per event, no subscription:

| Event | Price |
|---|---|
| Domain result (registration data + DNS for one domain) | **$0.001** ($1 per 1,000) |
| Email security check (add-on, only when enabled) | $0.0005 ($0.50 per 1,000) |
| Actor start (per run) | $0.002 |

For example, 10,000 domains with the email audit cost about $15, or $10 without it. Invalid domains and failed lookups are never charged, and you can set a maximum cost per run.

### Use cases

- **Domain name ideas**: check hundreds of names for availability across TLDs in one run.
- **Portfolio and brand monitoring**: expiry dates, registrar or nameserver changes, and lookalike domains.
- **Lead enrichment and sales**: mail provider (Google vs Microsoft), domain age and registrar for a list of company domains.
- **Email deliverability and security audits**: find domains without DMARC or with weak SPF.
- **Security and OSINT**: newly changed nameservers or MX records on watched domains.

### FAQ

**What is RDAP?** The Registration Data Access Protocol is ICANN's standardised, JSON-based successor to WHOIS. Registries publish it as an official public service. The Actor finds the right RDAP server for each TLD through IANA's bootstrap file and queries the registry directly.

**Why are registrant names missing?** Since GDPR most registries and registrars redact personal registrant data. You get the registrant organisation and country only where the registry publishes them (for example many .fr, .io and .uk organisations). Turn on `followRegistrarRdap` for .com/.net to also ask the registrar's RDAP server.

**Some ccTLDs have no expiry date.** Registries such as DENIC (.de), SIDN (.nl) and SWITCH (.ch) don't publish expiry dates. A few registries (for example .es and .pt) don't offer open WHOIS access at all. In that case the domain is still reported as registered from its DNS delegation, and `registration_error` explains what happened.

**Is "available" guaranteed?** It means the registry has no registration. Some names are still reserved, premium-priced or blocked by registry policy, so check with a registrar before you buy.

**How does the change monitor work?** With `onlyChanged`, each domain's key fields are saved in a named key-value store. Later runs output only domains that changed, with a `changes` list and the `previous` values. The first run outputs everything.

# Actor input Schema

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

One domain per line (you can also paste comma- or space-separated lists). URLs and <code>www.</code> are cleaned up automatically, e.g. <code>https://www.example.com/page</code> becomes <code>example.com</code>. Internationalised names are supported.

## `lookupRegistration` (type: `boolean`):

Registrar, creation, update and expiry dates, status codes, nameservers, DNSSEC and availability from the official registry RDAP service (ICANN's WHOIS replacement).

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

Some ccTLDs (for example .de, .io, .eu, .ch, .it, .co) have no RDAP service yet. Query the registry's public port-43 WHOIS instead (slower: one query per 1.5 s per registry).

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

For .com/.net and other thin registries, follow the link to the registrar's RDAP server to fill in registrant organisation and country when published (usually redacted for privacy). One extra request per domain.

## `dnsRecordTypes` (type: `array`):

Resolved over DNS-over-HTTPS (Cloudflare 1.1.1.1, with Google Public DNS as fallback). Leave empty to skip DNS.

## `emailSecurity` (type: `boolean`):

Detect the mail provider (Google Workspace, Microsoft 365, Proofpoint…) from MX records, parse SPF and DMARC, check common DKIM selectors, MTA-STS, TLS-RPT and BIMI, and return a 0–100 score with a list of issues. Charged as a separate add-on event per domain.

## `dkimSelectors` (type: `array`):

DKIM keys can't be listed, so we probe common selectors. Add your own (e.g. <code>mailchimp</code>, <code>k2</code>, <code>s2048</code>).

## `registrableDomainOnly` (type: `boolean`):

<code>shop.example.co.uk</code> is looked up as <code>example.co.uk</code> for registration data. DNS and email checks still use the host you entered.

## `onlyAvailable` (type: `boolean`):

Output only domains with no registration in the registry, which is ideal for checking name ideas in bulk.

## `expiringWithinDays` (type: `integer`):

0 = off. For example, 30 outputs only domains whose registration expires in the next 30 days.

## `onlyChanged` (type: `boolean`):

Remember each domain's registrar, expiry, status, nameservers, MX, A records, SPF and DMARC policy, and output only domains where something changed since the last run (with a <code>changes</code> list and the <code>previous</code> values). The first run outputs everything.

## `stateStoreName` (type: `string`):

Named key-value store for the change monitor. Use a different name for each independent watch list.

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

Registry servers are additionally rate-limited per host (and WHOIS per registry).

## Actor input object example

```json
{
  "domains": [
    "github.com",
    "apify.com",
    "bbc.co.uk",
    "spiegel.de",
    "thisdomainisprobablyfree-1729.com"
  ],
  "lookupRegistration": true,
  "whoisFallback": true,
  "followRegistrarRdap": false,
  "dnsRecordTypes": [
    "A",
    "AAAA",
    "MX",
    "NS",
    "TXT"
  ],
  "emailSecurity": true,
  "dkimSelectors": [
    "google",
    "selector1",
    "selector2",
    "k1",
    "default",
    "s1",
    "s2",
    "mail",
    "dkim"
  ],
  "registrableDomainOnly": true,
  "onlyAvailable": false,
  "expiringWithinDays": 0,
  "onlyChanged": false,
  "stateStoreName": "domain-rdap-dns-lookup-state",
  "maxConcurrency": 10
}
```

# Actor output Schema

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

Registration data, availability, DNS and email security per domain.

## `email` (type: `string`):

SPF, DMARC, DKIM, MTA-STS and mail provider per domain.

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

Counts (registered, unregistered, filtered, unchanged), WHOIS servers used, invalid or failed domains.

# 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": [
        "github.com",
        "apify.com",
        "bbc.co.uk",
        "spiegel.de",
        "thisdomainisprobablyfree-1729.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sysco32/domain-rdap-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": [
        "github.com",
        "apify.com",
        "bbc.co.uk",
        "spiegel.de",
        "thisdomainisprobablyfree-1729.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("sysco32/domain-rdap-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": [
    "github.com",
    "apify.com",
    "bbc.co.uk",
    "spiegel.de",
    "thisdomainisprobablyfree-1729.com"
  ]
}' |
apify call sysco32/domain-rdap-dns-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sysco32/domain-rdap-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/yks47fHVC4Z4Tg19g/builds/ZYaMSgA5IiwQ31AxG/openapi.json
