# DNS Lookup & WHOIS Domain Checker — SPF/DMARC, SSL Expiry (`forevertools/domain-whois-dns-ssl`) Actor

Bulk domain lookup (domain info & domain age): registrar, creation & expiration date (RDAP/WHOIS lookup), DNS records (A/AAAA/MX/NS/TXT/CAA), SPF & DMARC policy, SSL certificate issuer & days to expiration, plus warnings. Thousands of domains per run.

- **URL**: https://apify.com/forevertools/domain-whois-dns-ssl.md
- **Developed by:** [Forever Tools](https://apify.com/forevertools) (community)
- **Categories:** Developer 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 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

## Bulk Domain Checker — WHOIS/RDAP, DNS, SPF/DMARC, SSL Expiry

Paste a list of domains (or URLs) and get one clean row per domain with **registration, DNS, email-security and
SSL data** — plus ready-made warnings like `domain-expiring-soon`, `ssl-expiring-soon`, `no-dmarc`.

Great for: domain portfolio & renewal monitoring, SSL expiry alerts, email deliverability audits (SPF/DMARC),
lead/company enrichment (domain age, mail provider), security reviews, and AI agents that need domain facts.

### What you get per domain

| Group | Fields |
|---|---|
| Registration (RDAP, the official successor of WHOIS) | registrar, createdAt, updatedAt, expiresAt, daysUntilExpiry, domainAgeYears, status, nameservers, dnssec |
| DNS | a, aaaa, mx, ns, txt, caa, resolves |
| Email security | spf, dmarc, dmarcPolicy |
| SSL/TLS | sslValid, sslError, sslIssuer, sslSubject, sslAltNames, sslValidFrom, sslValidTo, sslDaysUntilExpiry, tlsProtocol |
| Warnings | domain-expiring-soon (<30d), ssl-expiring-soon (<14d), ssl-invalid, no-spf, no-dmarc, dmarc-policy-none, does-not-resolve, not-registered |

Every row also includes `input` (what you typed), `domain` (the normalized hostname), `registered`, `registeredDomain`
and `checkedAt` (ISO timestamp).

### Bulk WHOIS lookup (RDAP) for a list of domains

Traditional WHOIS is free-text and rate-limited per registry. This actor uses **RDAP**, the structured JSON protocol that
replaces WHOIS, and finds the right registry server automatically through the IANA bootstrap file. You get the registrar,
creation, update and expiry dates, status codes, nameservers and DNSSEC flag as separate fields, and the actor computes
`daysUntilExpiry` and `domainAgeYears` for you. If you pass a subdomain such as `blog.example.co.uk`, it walks up the labels
until it finds the registered domain.

### Check SSL certificate expiry for many domains

The actor opens a TLS connection to port 443 of each host and reads the certificate: issuer, subject, alternative names
(first 50), validity window, `sslDaysUntilExpiry`, whether it validates, and the negotiated TLS version. Failures are
reported (for example `sslError` with a timeout or certificate error code) and flagged as `ssl-invalid`. Certificates with
fewer than 14 days left get `ssl-expiring-soon`.

### SPF and DMARC checker in bulk

Email security fields come from DNS: the `v=spf1` TXT record, the `_dmarc` TXT record and the parsed DMARC policy
(`none`, `quarantine` or `reject`). Domains with no SPF or DMARC record, or a `p=none` policy, get warning flags, so you can
filter a large list down to the ones that need attention before a deliverability review.

### Use cases

- **Domain portfolio monitoring:** schedule a weekly run and filter rows with `domain-expiring-soon`.
- **SSL expiry monitoring:** catch certificates that are about to lapse across many client or internal sites.
- **Email deliverability audits:** list domains missing SPF/DMARC or still on `p=none`.
- **Lead and company enrichment:** domain age, nameservers and mail provider (via MX) for a prospect list.
- **Security and due diligence:** spot domains that no longer resolve, are not registered, or lack CAA records.
- **AI agents:** call it through the Apify MCP server when an agent needs verified domain facts.

### Input example

```json
{
  "domains": ["apify.com", "https://www.github.com/features", "example.org"],
  "checkRdap": true,
  "checkDns": true,
  "checkSsl": true,
  "maxConcurrency": 10
}
```

- `domains` — domains or URLs; URLs are reduced to the hostname, duplicates are removed.
- `checkRdap`, `checkDns`, `checkSsl` — switch each group of checks on or off (all default to true).
- `maxConcurrency` — domains checked in parallel, 1 to 25 (default 10).

### Output example

```json
{
  "domain": "github.com",
  "registrar": "MarkMonitor Inc.",
  "createdAt": "2007-10-09T18:20:50Z",
  "expiresAt": "2028-10-09T18:20:50Z",
  "daysUntilExpiry": 741,
  "mx": ["0 github-com.mail.protection.outlook.com"],
  "spf": "v=spf1 ip4:192.30.252.0/22 include:_netblocks.google.com ...",
  "dmarcPolicy": "quarantine",
  "sslIssuer": "Sectigo Limited",
  "sslDaysUntilExpiry": 62,
  "warnings": []
}
```

The example is shortened; real rows contain all the fields listed above. You can download the dataset as JSON, CSV, Excel or
HTML from the Apify console.

### Pricing

**$0.002 per domain** ($2 per 1,000) — registration + DNS + SSL all included. No subscription.
Examples: 1,000 domains = $2.00, 10,000 domains = $20.00, a 250-domain portfolio checked weekly = $0.50 per run.
Invalid input (rows with `error`) is **not charged**; unregistered domains are a real result and are charged.
Tip: schedule it weekly on your domain list to get renewal/SSL alerts.

### Limitations

- Registration data comes from the official RDAP servers listed by IANA. A few country TLDs (e.g. `.de`) don't
  offer RDAP; for those `rdapError` is set and DNS/SSL data is still returned.
- RDAP does not expose personal registrant contact details here; the actor returns registrar and technical registration data only.
- SSL is checked on port 443 only, so services on other ports, or hosts without HTTPS, show an SSL error.
- SPF and DMARC are read for the registered (apex) domain; DKIM selectors are not checked.
- DNS is resolved via public resolvers (1.1.1.1 / 8.8.8.8), so private or split-horizon DNS records are not visible.
- Registries can rate-limit or time out; in that case `rdapError` explains it and the other checks still run.
- Built and maintained with AI assistance. Problems or requests: use the Issues tab.

### FAQ

**How do I check when a domain expires in bulk?**
Add your domains to the input and run with registration checks on. Each row has `expiresAt` and `daysUntilExpiry`, and rows under 30 days get `domain-expiring-soon`.

**Is RDAP the same as WHOIS?**
RDAP is the standardized, JSON-based successor to WHOIS. It returns the same kind of registration data (registrar, dates, status, nameservers) in a structured form.

**How can I find domains with no DMARC or SPF record?**
Run with DNS checks on and filter the dataset for the `no-dmarc`, `no-spf` or `dmarc-policy-none` warnings.

**Can I monitor SSL certificate expiry automatically?**
Yes. Save your domain list as a task, add an Apify schedule (for example weekly), and filter for `ssl-expiring-soon` or `ssl-invalid`, or connect the dataset to Zapier, Make or n8n.

**What happens if a domain is invalid or unregistered?**
Invalid input gets a row with `error: "invalid domain"`. A domain with no RDAP record gets `registered: false` and the `not-registered` warning.

**Do I have to run all three checks?**
No. Turn off `checkRdap`, `checkDns` or `checkSsl` to run only what you need.

### Related tools

Other actors by the same developer (same flat pay-per-result pricing, no subscription):

- [Apple App Store Reviews Scraper (Multi-Country)](https://apify.com/forevertools/apple-app-store-reviews)
- [Article Extractor – Clean Text & Markdown for LLM/RAG](https://apify.com/forevertools/article-extractor)
- [Company Jobs Scraper: Workday, Greenhouse, Lever, Ashby](https://apify.com/forevertools/ats-company-jobs)
- [Bulk PageSpeed Insights & Core Web Vitals Checker](https://apify.com/forevertools/pagespeed-core-web-vitals)
- [PDF to Text Extractor (Bulk, with Metadata)](https://apify.com/forevertools/pdf-to-text-extractor)
- [Website SEO Audit Crawler](https://apify.com/forevertools/website-seo-audit)
- [Sitemap Extractor & Bulk URL Status Checker](https://apify.com/forevertools/sitemap-url-status-checker)
- [Website Tech Stack Detector (CMS, Framework, Analytics)](https://apify.com/forevertools/website-tech-stack-detector)
- [Website Screenshot – Bulk Full Page PNG, JPEG & PDF](https://apify.com/forevertools/website-screenshot)

### Integrations

Run it from the Apify API, a schedule, or no-code tools: the Apify apps for **Zapier**, **Make** and **n8n** can start any public actor ("Run Actor") and read its dataset. AI agents can call it through the **Apify MCP server**.

# Actor input Schema

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

Domains or URLs to check (example.com, https://www.example.com/page); only the host is used. Duplicates are removed. One row per domain: registrar, creation/expiry dates and days until expiry (RDAP), A/MX/NS/TXT records, SPF/DMARC, SSL issuer and expiry, plus a `warnings` list. Invalid input returns a row with `error` and is not charged.

## `checkRdap` (type: `boolean`):

Registrar, creation/expiry dates, status, nameservers, DNSSEC.

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

A, AAAA, MX, NS, TXT, CAA, SPF, DMARC.

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

Issuer, validity, days until expiry, TLS version.

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

Domains checked in parallel.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "github.com"
  ],
  "checkRdap": true,
  "checkDns": true,
  "checkSsl": true,
  "maxConcurrency": 10
}
```

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

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

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

```

## MCP server setup

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

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/8OagpFYmNJ1Xh4qec/builds/3hvT5rddEHSS2JbK6/openapi.json
