# Domain WHOIS, DNS & SSL Checker - Bulk Expiry & Email Security (`paperlinenstudio/domain-whois-dns-checker`) Actor

Check any list of domains in bulk: registration and expiry dates, registrar and status (official RDAP/WHOIS), DNS records (A, AAAA, MX, NS, TXT, CAA), SPF and DMARC, SSL certificate issuer and expiry, HTTPS redirect. Flags expiring domains and certificates. No API key needed.

- **URL**: https://apify.com/paperlinenstudio/domain-whois-dns-checker.md
- **Developed by:** [Paper & Linen Studio](https://apify.com/paperlinenstudio) (community)
- **Categories:** Developer tools, SEO tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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 & SSL Checker – Bulk Expiry & Email Security

Paste a list of domains (or URLs) and get **one row per domain** with everything you normally check in five different tools:

- **Registration (WHOIS / RDAP)**: registered or not, registrar, creation date, **expiry date and days left**, last change, domain status, name servers, DNSSEC
- **DNS records**: A, AAAA, MX, NS, TXT, CAA (also CNAME and SOA on request)
- **Email security**: SPF record, DMARC record and policy (`none` / `quarantine` / `reject`)
- **SSL certificate**: valid or not, issuer, valid from / to, **days until expiry**, alternative names, TLS version
- **Website**: HTTP status, final URL, HTTPS redirect, HSTS, server header, response time
- **`issues[]`**: plain-English warnings such as "Domain expires in 12 days", "SSL certificate invalid: certificate has expired", "No DMARC record" or "Website does not redirect to HTTPS"

No API key, no proxy and no browser needed. Registration data comes from the **official registry RDAP services** (the modern, structured successor of WHOIS), so there is no fragile WHOIS-text parsing and no third-party WHOIS API.

### What you can use it for

- **Domain portfolio monitoring**: run it on a schedule and get warned before a domain or certificate expires.
- **Agency / IT client checks**: audit all client domains at once for expiring certificates, missing HTTPS redirects, and missing SPF or DMARC.
- **Email deliverability audits**: since Google and Yahoo require SPF and DMARC from bulk senders, find the domains without them.
- **Lead enrichment and qualification**: domain age, registrar, mail provider (MX), hosting (A / NS) and whether the website is live.
- **Domain research**: check whether domains are still unregistered (`registered: false`).

### Input

| Field | Description |
|---|---|
| `domains` | Domains, subdomains or URLs, e.g. `example.com`, `shop.example.de`, `https://www.example.co.uk/page` |
| `checkWhois` | Registration data from RDAP (default `true`) |
| `checkDns` / `dnsRecordTypes` | DNS records and which types (default A, AAAA, MX, NS, TXT, CAA) |
| `checkEmailSecurity` | SPF + DMARC (default `true`) |
| `checkSsl` | SSL certificate on port 443 (default `true`) |
| `checkHttp` | Homepage status / redirects / HSTS (default `true`) |
| `expiryWarningDays` | Flag domains expiring within N days (default 30) |
| `maxItems`, `maxConcurrency`, `timeoutSecs` | Limits |

```json
{"domains": ["github.com", "bbc.co.uk", "tchibo.de"], "expiryWarningDays": 60}
```

Registration data is always looked up for the **registrable domain** (`shop.example.co.uk` → `example.co.uk`, using the Public Suffix List). DNS A/AAAA records, the SSL certificate and the HTTP check use the host you entered. Internationalised domains (e.g. `münchen.de`) are converted to punycode.

### Output (real example, shortened)

```json
{
  "input": "github.com",
  "host": "github.com",
  "domain": "github.com",
  "tld": "com",
  "rdapServer": "https://rdap.verisign.com/com/v1/",
  "registered": true,
  "registrar": "MarkMonitor Inc.",
  "registrarIanaId": "292",
  "createdAt": "2007-10-09T18:20:50+00:00",
  "updatedAt": "2026-09-07T09:22:52+00:00",
  "expiresAt": "2028-10-09T18:20:50+00:00",
  "domainStatus": [
    "client delete prohibited",
    "client transfer prohibited",
    "client update prohibited"
  ],
  "nameservers": [
    "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"
  ],
  "dnssec": false,
  "domainAgeDays": 6965,
  "daysUntilExpiry": 706,
  "dns": {
    "A": [
      "140.82.114.4"
    ],
    "AAAA": [],
    "MX": [
      {
        "priority": 0,
        "host": "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": [
      "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",
      "calendly-site-verification=at0DQARi7IZvJtXQAWhMqpmIzpvoBNF7aam5VKKxP"
    ],
    "CAA": [
      "0 issue \"digicert.com\"",
      "0 issue \"globalsign.com\"",
      "0 issue \"letsencrypt.org\"",
      "0 issue \"sectigo.com\"",
      "0 issuewild \"digicert.com\"",
      "0 issuewild \"letsencrypt.org\"",
      "0 issuewild \"sectigo.com\""
    ]
  },
  "dnsResolves": true,
  "registeredSource": "rdap",
  "emailSecurity": {
    "spf": "v=spf1 ip4:192.30.252.0/22 include:spf.protection.outlook.com include:_netblocks.google.co … ~all",
    "spfRecordCount": 1,
    "dmarc": "v=DMARC1; p=quarantine; sp=reject; pct=100; rua=mailto:dmarc@github.com; ruf=mailto:dmarc@github.com; fo=1",
    "dmarcPolicy": "quarantine",
    "hasMx": true
  },
  "ssl": {
    "host": "github.com",
    "valid": true,
    "issuer": "Sectigo Limited",
    "subject": "github.com",
    "validFrom": "2026-10-30T00:00:00+00:00",
    "validTo": "2027-01-27T23:59:59+00:00",
    "daysUntilExpiry": 85,
    "subjectAltNames": [
      "github.com",
      "www.github.com"
    ],
    "tlsVersion": "TLSv1.3",
    "error": null
  },
  "http": {
    "url": "https://github.com/",
    "statusCode": 200,
    "finalUrl": "https://github.com/",
    "redirectsToHttps": true,
    "server": "github.com",
    "hsts": true,
    "responseTimeMs": 77,
    "error": null
  },
  "issues": [],
  "errors": [],
  "checkedAt": "2026-11-03T13:24:18+00:00"
}
```

The run also writes a **SUMMARY** record to the key-value store (domains checked, registered / not registered, with issues, expiring soon, SSL problems, without DMARC). Export the results as JSON, CSV or Excel, or read them through the Apify API.

### Coverage and limitations (please read)

- **RDAP coverage depends on the registry.** All generic TLDs (.com, .net, .org, .info, .shop, .dev, …) and many ccTLDs (.uk, .fr, .nl, .pl, .cz, .no, .fi, .ca, .au, .br, .ch, …) publish RDAP with full dates and registrar.
  - **.de (DENIC)** publishes only the status, name servers and last change: **no creation or expiry date and no registrar**.
  - Some ccTLDs have **no public RDAP service** at all (e.g. **.at, .eu, .io, .it, .es, .co**). For those, `registered` is derived from DNS (`registeredSource: "dns"`), and a note is added to `errors`.
- **Domain holder contact data is never collected.** Most registries redact it under the GDPR anyway.
- `registered: false` means the registry answered "not found". This usually means available, but premium, reserved or blocked names can still not be registrable.
- DNS is resolved via DNS-over-HTTPS (Google, with Cloudflare as fallback), so you see public DNS as the internet sees it.
- The SSL check uses the system trust store. Self-signed or incomplete certificate chains are reported as `valid: false` with the reason.
- Respect the registries' terms of use. For example, DENIC permits use of its RDAP data only for technical or administrative purposes, not for advertising. Requests per registry are rate-limited by the Actor.

### Pricing

Free to use. You only pay for the Apify platform usage of your run, which is very low: in our test run, 20 domains with all checks took 29 seconds (including start-up) at 256 MB memory and used less than $0.0001 of platform credit.

***

### Deutsch: Kurzbeschreibung

**Domain WHOIS, DNS & SSL Checker**: Liste von Domains rein, pro Domain eine Zeile raus:

- Registrierung (RDAP/WHOIS): Registrar, Erstellungs- und Ablaufdatum, Status, Nameserver
- DNS-Einträge
- SPF und DMARC
- SSL-Zertifikat mit Restlaufzeit
- HTTPS-Weiterleitung
- verständliche Warnungen in `issues`

Ideal für Agenturen, IT-Dienstleister und Domain-Portfolios, z. B. als regelmäßiger Zeitplan, der vor ablaufenden Zertifikaten oder fehlendem DMARC warnt. Hinweis: DENIC (.de) veröffentlicht per RDAP keine Ablaufdaten und keinen Registrar; für .de-Domains liefert der Actor Status, Nameserver, DNS, E-Mail-Sicherheit und SSL.

# Actor input Schema

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

Domains, subdomains or full URLs (e.g. example.com, shop.example.de, https://www.example.co.uk/page). Registration data is looked up for the registrable domain (example.co.uk); DNS A/AAAA, SSL and HTTP checks use the host you enter. Duplicates are removed.

## `checkWhois` (type: `boolean`):

Look up registrar, creation, expiry and last-changed dates, domain status, name servers and DNSSEC from the official registry RDAP service. Contact data of domain holders is never collected.

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

Resolve the DNS record types selected below (via DNS-over-HTTPS).

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

Which record types to return. Allowed: A, AAAA, CNAME, MX, NS, TXT, CAA, SOA.

## `checkEmailSecurity` (type: `boolean`):

Find the SPF and DMARC records, read the DMARC policy and flag missing or weak setups.

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

Connect on port 443 and read the certificate: validity, issuer, expiry date, days left, alternative names, TLS version.

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

Request the homepage: status code, final URL after redirects, HTTPS redirect, HSTS header, server header, response time.

## `expiryWarningDays` (type: `integer`):

Add an issue when the domain expires within this many days. SSL certificates are flagged at this value or 14 days, whichever is lower (most certificates renew automatically ~30 days before expiry).

## `maxItems` (type: `integer`):

Stop after this many domains.

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

How many domains are checked in parallel. Requests per registry are limited separately to stay polite.

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

Timeout for each RDAP, DNS, SSL or HTTP request.

## Actor input object example

```json
{
  "domains": [
    "github.com",
    "bbc.co.uk",
    "tchibo.de"
  ],
  "checkWhois": true,
  "checkDns": true,
  "dnsRecordTypes": [
    "A",
    "AAAA",
    "MX",
    "NS",
    "TXT",
    "CAA"
  ],
  "checkEmailSecurity": true,
  "checkSsl": true,
  "checkHttp": true,
  "expiryWarningDays": 30,
  "maxItems": 100000,
  "maxConcurrency": 10,
  "timeoutSecs": 15
}
```

# Actor output Schema

## `items` (type: `string`):

No description

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

// Run the Actor and wait for it to finish
const run = await client.actor("paperlinenstudio/domain-whois-dns-checker").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",
        "bbc.co.uk",
        "tchibo.de",
    ] }

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

```

## MCP server setup

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

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/Dnb6SrtY63kXKCf7c/builds/1qEDyfVZmlKWrDYnt/openapi.json
