# Domain Checker – WHOIS/RDAP, DNS, SSL & Email Security in Bulk (`gazidev/domain-intel`) Actor

Bulk domain lookup: registrar, creation and expiry dates (RDAP with WHOIS fallback), DNS records (A, MX, NS, TXT, CAA, SOA), SPF/DMARC/DKIM, email provider, SSL certificate expiry, HTTP redirects and HSTS, plus ready-made risk flags. One row per domain, no API keys.

- **URL**: https://apify.com/gazidev/domain-intel.md
- **Developed by:** [Cemal Atakli](https://apify.com/gazidev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 domain analyzeds

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 Checker – WHOIS/RDAP, DNS, SSL & Email Security in Bulk

Check **hundreds or thousands of domains at once** and get **one clean row per domain** covering registration (WHOIS/RDAP), DNS, email security, SSL certificate and website status:

- **Registration (WHOIS / RDAP):** registrar, IANA ID, abuse contact, **creation, update and expiry dates**, **days to expiry**, domain age, status codes (clientTransferProhibited, hold…), name servers and **DNSSEC**. It uses the official **RDAP** protocol through the IANA bootstrap, and **port-43 WHOIS** for ccTLDs without RDAP (.com.tr, .co.jp, .it, .eu, .ru, .se, .be, .at, .cn…).
- **DNS records:** A, AAAA, MX, NS, TXT, CAA and SOA, plus verification tokens (google, facebook, openai…).
- **Email security:** **SPF** (parsed: all qualifier, includes, lookup count), **DMARC** (policy, sp, pct, rua), **DKIM** (about 25 common selectors probed), MTA-STS, TLS-RPT and BIMI. It also shows the **email provider** taken from MX/SPF (Google Workspace, Microsoft 365, Zoho, Yandex 360, Proton, Fastmail, GoDaddy…), any **security gateway** in front of it (Proofpoint, Mimecast, Barracuda, Cisco…) and sending services (Mailgun, SendGrid, HubSpot, Amazon SES…).
- **SSL/TLS certificate:** a real handshake on port 443 returns issuer, subject, SANs, valid from/to, **days left**, TLS protocol and cipher, key type, and whether the certificate is valid, expired or self-signed, with the reason when validation fails.
- **Website (HTTP):** final URL after redirects, the redirect chain, status code, page title, `Server` header, **HSTS**, whether http redirects to https, and the security headers present (CSP, X-Frame-Options…).
- **Ready-made flags** such as `domain_expiring_soon`, `ssl_expiring_soon`, `ssl_expired`, `missing_dmarc`, `dmarc_policy_none`, `missing_spf`, `spf_too_permissive`, `no_https_redirect`, `missing_hsts` and `not_registered`. You can filter a spreadsheet by them straight away.

No API keys and no browser. It runs on public protocols only (RDAP, WHOIS, DNS, TLS, HTTP), so it is fast and cheap: **$0.80 per 1,000 domains**.

### Use cases

- **Domain & SSL expiry monitoring.** Schedule a daily or weekly run over your domain portfolio or your clients' domains, then filter on `domain_expiring_soon` / `ssl_expiring_soon` (thresholds are configurable) and send the result to Slack or email with an Apify integration.
- **Lead enrichment.** Add registrar, domain age, email provider (Google Workspace vs Microsoft 365 vs others), security gateway, sending tools (HubSpot, Mailchimp, Salesforce…) and website title to a list of company domains. Useful for sales targeting and tech-based segmentation.
- **Email deliverability & security audit.** Find every domain in a list with no DMARC, `p=none`, a permissive SPF (`+all` / `?all`), several SPF records or more than 10 SPF lookups, or no DKIM under the common selectors.
- **Security / attack-surface review.** Find expired, self-signed or mismatched certificates, old TLS (1.0/1.1), missing HSTS, no http→https redirect, missing CAA and unsigned DNSSEC.
- **Domain research & availability.** `registered: false` means the registry has no record, so the name is probably available. You can also check registrar and age before buying, and spot domains in `pendingDelete`/`redemption`.
- **M\&A, brand protection, IT inventory.** Get one normalized table across gTLDs and ccTLDs instead of dozens of different WHOIS formats.

### Input

The only required field is a list of domains. URLs and email addresses are accepted: `https://www.example.com/page` and `jane@example.com` both become `example.com`. Registration, DNS and email checks run on the registrable domain (the Public Suffix List handles `co.uk`, `com.tr`, `com.au`…). SSL and HTTP checks run on the exact host you entered.

```json
{
  "domains": ["apify.com", "github.com", "bbc.co.uk"],
  "checkRegistration": true,
  "checkDns": true,
  "checkDkim": true,
  "checkSsl": true,
  "checkHttp": true,
  "domainExpiryWarningDays": 30,
  "sslExpiryWarningDays": 14
}
```

Other options:

- **Bulk input:** a `bulkText` box (lines, commas or a whole CSV export) or a `sourceFileUrl` pointing to a TXT/CSV file, such as a published Google Sheet.
- **Toggles:** turn each check on or off. For example, keep only SSL + HTTP for a certificate monitor.
- **Advanced:** extra DKIM selectors, custom DNS resolvers, `followRegistrarRdap` (can add registrant organization/country for .com/.net when not redacted), `includeRawWhois`, `maxDomains`, `maxConcurrency` (default 10) and `timeoutSecs`.

### Output

One dataset item per domain. It has flat columns for spreadsheets, plus nested `registration`, `dns`, `ssl` and `http` objects with the full details. The **Overview** and **Email security** tabs show the most useful columns as tables. Excerpt from a real run (full items in `SAMPLE_OUTPUT.json`):

| domain | registrar | expires | days | email provider | SPF | DMARC | SSL issuer | SSL days | flags |
|---|---|---|---|---|---|---|---|---|---|
| apify.com | Amazon Registrar, Inc. | 2035-06-02 | 3167 | Google Workspace | -all | reject | Amazon | 109 | – |
| github.com | MarkMonitor Inc. | 2028-10-09 | 740 | Microsoft 365 | ~all | quarantine | Sectigo | 61 | dnssec\_unsigned |
| bbc.co.uk | British Broadcasting Corporation | 2034-12-13 | 2996 | (gateway: Broadcom) | ~all | reject | GlobalSign | 116 | dnssec\_unsigned, dkim\_not\_found\_common\_selectors |
| trendyol.com.tr (WHOIS) | ODTÜ Geliştirme Vakfı | 2029-07-08 | 1012 | Google Workspace (from SPF) | ~all | missing | Google Trust Services | 38 | no\_mx, missing\_dmarc, … |
| expired.badssl.com | MarkMonitor Inc. | 2027-04-07 | 189 | Google Workspace | missing | missing | COMODO | -4188 | ssl\_expired, ssl\_invalid, … |
| thisdomaindoesnotexist-xyz987.com | – | – | – | – | – | – | – | – | not\_registered, dns\_nxdomain, ssl\_unavailable, website\_unreachable |

```json
{
  "domain": "apify.com",
  "registered": true,
  "registrar": "Amazon Registrar, Inc.",
  "createdAt": "2009-06-02T17:14:10Z",
  "expiresAt": "2035-06-02T17:14:10Z",
  "daysToExpiry": 3167,
  "emailProvider": "Google Workspace",
  "spf": "-all",
  "dmarcPolicy": "reject",
  "dkimSelectors": "google",
  "sslIssuer": "Amazon",
  "sslDaysLeft": 109,
  "finalUrl": "https://apify.com/",
  "httpStatus": 200,
  "flags": [],
  "registration": { "registrarIanaId": "468", "status": ["client transfer prohibited"], "dnssec": true, "source": "rdap", "...": "..." },
  "dns": { "a": ["3.160.57.105"], "mx": [{"priority": 1, "host": "aspmx.l.google.com"}], "email": { "spf": {"includes": ["_spf.google.com", "mailgun.org"]}, "dmarc": {"policy": "reject", "rua": ["mailto:dmarc-reports@apify.com"]}, "mtaSts": true, "sendingServices": ["Google Workspace", "Mailgun", "Amazon SES", "HubSpot"] }, "...": "..." },
  "ssl": { "valid": true, "protocol": "TLSv1.3", "subject": "*.apify.com", "sans": ["*.apify.com", "apify.com"], "validTo": "2027-01-16T23:59:59Z", "...": "..." },
  "http": { "finalUrl": "https://apify.com/", "status": 200, "title": "Apify: Marketplace of ready-to-run tools for AI", "hsts": {"maxAge": 15768000}, "httpRedirectsToHttps": true, "...": "..." }
}
```

#### Flags reference

| Flag | Meaning |
|---|---|
| `not_registered` | Registry returned "not found". The name is probably available. |
| `domain_expired` / `domain_expiring_soon` | Expiry date is in the past / within `domainExpiryWarningDays` (default 30) |
| `domain_on_hold`, `domain_pending_delete` | Registry status contains hold / pendingDelete / redemption |
| `dnssec_unsigned` | Delegation is not DNSSEC-signed |
| `dns_nxdomain`, `no_a_record` | Domain does not resolve / has no A/AAAA record |
| `no_mx`, `missing_spf`, `spf_multiple_records`, `spf_too_permissive`, `spf_too_many_lookups` | Email sending/receiving configuration problems |
| `missing_dmarc`, `dmarc_policy_none` | No DMARC record / DMARC only monitoring (`p=none`) |
| `dkim_not_found_common_selectors` | No DKIM key under the ~25 common selectors (custom selectors can't be discovered) |
| `missing_caa` | No CAA record restricting which CAs may issue certificates |
| `ssl_unavailable`, `ssl_expired`, `ssl_expiring_soon`, `ssl_invalid`, `ssl_self_signed`, `weak_tls_protocol` | Certificate problems (`sslExpiryWarningDays`, default 14) |
| `website_unreachable`, `website_http_error`, `no_https_redirect`, `missing_hsts` | Website problems |

### Pricing

Pay per event. You pay only for what you use and there is no subscription.

| Event | Price |
|---|---|
| Domain analyzed | **$0.0008** ($0.80 per 1,000 domains) |
| Actor start | $0.0002 (once per run) |

Invalid inputs and domains where every check failed are **not charged**. A lookup that comes back "not registered" is charged, because it is a real result (availability). Set a *Maximum cost per run* and the Actor stops cleanly when it is reached.

#### Compared with other Apify Store actors (per 1,000 domains, Sep 2026)

| Actor | Price / 1,000 | What you get |
|---|---|---|
| **This Actor** | **$0.80** | RDAP/WHOIS + DNS + SPF/DMARC/DKIM + email provider + SSL + HTTP + flags |
| santamaria-automations/domain-whois-dns | $3.00 (+$0.001/run) | WHOIS + DNS |
| ryanclinton/whois-domain-lookup | $3.00 | WHOIS |
| agenscrape/whois-domain-lookup | $2.50 | WHOIS |
| automation-lab/domain-availability-checker | $2.30 (+$0.035/run) | availability |
| pink\_comic/whois-domain-lookup | $2.00 | WHOIS |

### Use with AI agents (Apify MCP)

This Actor works as a tool for AI agents such as Claude, ChatGPT, Cursor and LangChain through the **Apify MCP server** (`https://mcp.apify.com`). Add it to your MCP client and the agent can call it with `{"domains": [...]}`. It gets back compact, typed JSON with flat summary fields and explicit `flags`, so an agent can answer questions like these without parsing WHOIS text:

- "Which of these 200 client domains expire in the next 30 days?"
- "Does acme.com use Google Workspace or Microsoft 365, and is its DMARC enforced?"
- "Audit our domains for missing DMARC, weak SPF and expiring certificates."

You can also call it directly over the API: `POST https://api.apify.com/v2/acts/gazidev~domain-intel/run-sync-get-dataset-items?token=…` with the input JSON returns the rows in one request, which suits small lists.

### FAQ

**Why RDAP instead of WHOIS?** RDAP is the IETF/ICANN-standard replacement for WHOIS. It returns structured JSON, so dates and statuses are reliable, and it is mandatory for all gTLDs. For ccTLDs that publish no RDAP, the Actor falls back to the registry's port-43 WHOIS and parses the common fields.

**Why is the registrant name empty?** Since GDPR, registries and registrars redact personal registrant data. The Actor returns the registrant **organization** and **country** only when the registry publishes them. It does not collect personal data.

**Some ccTLDs return few fields.** Some registries publish very little: DENIC (.de) has no creation or expiry date, EURid (.eu) and nic.at (.at) have no expiry, and JPRS (.jp) has no registrar. Some block automated WHOIS entirely. In those cases the row still contains DNS, email, SSL and HTTP data, and `registration.error` explains what happened.

**Is "not registered" a guarantee the domain is available?** No. It means the registry has no record. Premium, reserved and blocked names can still be unavailable, so confirm with a registrar before buying.

**How many DKIM selectors are checked?** About 25 common ones (Google, Microsoft `selector1/2`, Mailchimp `k1`, `default`, `s1`…). You can add your own. DKIM has no discovery mechanism, so "not found" only means none of those selectors matched.

**Rate limits?** Requests are throttled per RDAP/WHOIS server and retried with backoff on 429/5xx. For very large single-ccTLD lists (for example 10,000 × .de), some WHOIS registries may throttle. Those rows still return all other checks.

**How fast is it?** About 1–2 domains per second at the default 512 MB / concurrency 10. For big lists, raise memory to 1–2 GB and concurrency to 20–30.

# Actor input Schema

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

Domains to check, e.g. `example.com`. URLs (`https://www.example.com/page`) and email addresses (`jane@example.com`) are accepted too: registration, DNS and email checks run on the registrable domain, SSL and HTTP checks on the exact host you entered.

## `bulkText` (type: `string`):

Paste a long list: one domain per line, comma/semicolon separated, or a whole CSV export (the first cell that looks like a domain, URL or email in each row is used).

## `sourceFileUrl` (type: `string`):

Public URL of a .txt or .csv file with domains (e.g. a Google Sheets 'Publish to web' CSV link).

## `checkRegistration` (type: `boolean`):

Registrar, creation/update/expiry dates, days to expiry, status codes, name servers and DNSSEC. Uses the official RDAP protocol (IANA bootstrap) and falls back to port-43 WHOIS for TLDs without RDAP.

## `checkDns` (type: `boolean`):

A, AAAA, MX, NS, TXT, CAA and SOA records; SPF, DMARC, MTA-STS, TLS-RPT and BIMI; email provider detected from MX/SPF (Google Workspace, Microsoft 365, Zoho...).

## `checkDkim` (type: `boolean`):

Look up ~25 common DKIM selectors (google, selector1/2, k1, default, s1...). DKIM has no discovery mechanism, so a miss means 'not found under common selectors', not 'no DKIM'.

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

Additional selectors to try, e.g. `mailo`, `cm`, `scph0922`.

## `checkSsl` (type: `boolean`):

TLS handshake on port 443: validity, issuer, subject, SANs, valid from/to, days left, protocol and cipher.

## `checkHttp` (type: `boolean`):

Final URL after redirects, status code, page title, Server header, HSTS, http->https redirect and common security headers.

## `domainExpiryWarningDays` (type: `integer`):

Add the `domain_expiring_soon` flag when the domain expires within this many days.

## `sslExpiryWarningDays` (type: `integer`):

Add the `ssl_expiring_soon` flag when the certificate expires within this many days.

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

Use port-43 WHOIS for TLDs that have no RDAP service (e.g. .com.tr, .co.jp, .it, .eu, .ru).

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

For thin registries like .com/.net, also fetch the registrar's RDAP record, which sometimes adds registrant organization and country (when not redacted). Slower.

## `includeRawWhois` (type: `boolean`):

Add the raw WHOIS answer (up to 4,000 characters) for domains looked up via WHOIS.

## `dnsResolvers` (type: `array`):

Optional resolver IPs, e.g. `1.1.1.1`, `8.8.8.8`. Empty = system resolver.

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

Stop after this many domains (0 = no limit).

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

Domains processed in parallel. RDAP/WHOIS servers are additionally rate-limited per server.

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

Timeout for each network request (RDAP, WHOIS, DNS, TLS, HTTP).

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "github.com",
    "bbc.co.uk"
  ],
  "checkRegistration": true,
  "checkDns": true,
  "checkDkim": true,
  "checkSsl": true,
  "checkHttp": true,
  "domainExpiryWarningDays": 30,
  "sslExpiryWarningDays": 14,
  "whoisFallback": true,
  "followRegistrarRdap": false,
  "includeRawWhois": false,
  "maxDomains": 0,
  "maxConcurrency": 10,
  "timeoutSecs": 10
}
```

# Actor output Schema

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

No description

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

No description

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

// Run the Actor and wait for it to finish
const run = await client.actor("gazidev/domain-intel").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",
        "github.com",
        "bbc.co.uk",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("gazidev/domain-intel").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",
    "github.com",
    "bbc.co.uk"
  ]
}' |
apify call gazidev/domain-intel --silent --output-dataset

```

## MCP server setup

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

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/dVahDxKMEYjfoOwMA/builds/nfE8K8gaKowN7jEdg/openapi.json
