# Domain Lookup - WHOIS/RDAP, DNS, SSL & Email Security (`kantolabs/domain-whois-dns-ssl-lookup`) Actor

Bulk domain report in one call: registrar, creation and expiry dates, domain age and availability (RDAP/WHOIS), all DNS records, SSL certificate validity and expiry, SPF/DKIM/DMARC email security grade and email provider. Pay per domain.

- **URL**: https://apify.com/kantolabs/domain-whois-dns-ssl-lookup.md
- **Developed by:** [Kanto Labs](https://apify.com/kantolabs) (community)
- **Categories:** Developer tools, Lead generation, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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 Lookup - WHOIS/RDAP, DNS, SSL Certificate & Email Security in One Report

Get a **complete report for any list of domains in one run**: who the registrar is, when the domain
was created and when it expires, whether it is **registered or available**, all of its **DNS
records**, whether its **SSL certificate** is valid and how many days are left, and how well its
email is protected (**SPF, DKIM, DMARC**, with an A-F grade and the detected email provider).

Other actors split this into four separate tools. Here it is **one row per domain, one low price**,
from official sources only: registry RDAP (the ICANN successor of WHOIS, with classic WHOIS as a
fallback), public DNS and a normal TLS handshake.

### What you can use it for

- **Lead enrichment and qualification** - company age, email provider (Google Workspace, Microsoft 365...), mail security maturity.
- **Domain portfolio monitoring** - schedule it daily and alert when a domain or certificate is about to expire.
- **Security and deliverability audits** - find clients with missing DMARC, weak SPF (`+all`, `?all`) or expired certificates.
- **Domain availability checks** - `registered: false` means the name is free to register.
- **Brand protection and due diligence** - check lookalike domains, registrars and creation dates.
- **AI agents** - one tool call answers "who owns / hosts / secures this domain?" via the Apify MCP server.

### What is checked

| Area | Fields |
|---|---|
| Registration (RDAP / WHOIS) | `registered`, `registrar`, `registrarIanaId`, `createdDate`, `expiresDate`, `updatedDate`, `domainAgeDays`, `daysUntilExpiry`, `status`, `registryNameservers`, `dnssec` |
| DNS | A, AAAA, MX, NS, TXT, CAA, SOA, `www` CNAME/A (via 1.1.1.1 / 8.8.8.8 / 9.9.9.9) |
| SSL / TLS | `valid`, verification error, issuer, subject, `validFrom`, `validTo`, `daysUntilExpiry`, SAN list, TLS version |
| Email security | SPF record + `all` qualifier, DMARC record + policy + reporting, DKIM on 12 common selectors, MTA-STS, TLS-RPT, BIMI, `emailProvider`, 0-100 `score`, A-F `grade` |
| Summary | `issues` - a plain-English list of problems found |

No personal data is collected: registrant names, emails and addresses are not read or returned.

### Input

| Field | What it does | Default |
|---|---|---|
| `domains` | Domains, URLs or email addresses (reduced to the registrable domain) | `apify.com`, `github.com`, `bbc.co.uk` |
| `includeWhois` | Registration data | `true` |
| `includeDns` | DNS records | `true` |
| `includeSsl` | SSL certificate | `true` |
| `includeEmailSecurity` | SPF / DKIM / DMARC report | `true` |
| `maxConcurrency` | Domains processed in parallel | `10` |

```json
{
    "domains": ["stripe.com", "https://www.shopify.com/pricing", "ceo@example.org"]
}
```

### Output

One dataset item per domain. Real output from a test run (the TXT and SAN lists are trimmed):

```json
{
    "input": "apify.com",
    "domain": "apify.com",
    "registered": true,
    "registrySource": "rdap",
    "registrar": "Amazon Registrar, Inc.",
    "registrarIanaId": "468",
    "createdDate": "2009-06-02T17:14:10Z",
    "expiresDate": "2035-06-02T17:14:10Z",
    "updatedDate": "2026-05-16T16:53:04Z",
    "domainAgeDays": 6321,
    "daysUntilExpiry": 3174,
    "status": ["client transfer prohibited"],
    "registryNameservers": ["ns-1225.awsdns-25.org", "ns-1928.awsdns-49.co.uk", "ns-449.awsdns-56.com", "ns-839.awsdns-40.net"],
    "dnssec": true,
    "dns": {
        "a": ["3.170.42.100", "3.170.42.109", "3.170.42.68", "3.170.42.76"],
        "mx": ["1 aspmx.l.google.com", "5 alt1.aspmx.l.google.com", "5 alt2.aspmx.l.google.com"],
        "txt": ["openai-domain-verification=dv-WTM7Nna92Owwh4sgmDOVUyyt"],
        "caa": ["0 issue \"amazonaws.com\"", "0 issue \"letsencrypt.org\""],
        "soa": "ns-839.awsdns-40.net. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
    },
    "mxHosts": ["aspmx.l.google.com", "alt1.aspmx.l.google.com", "alt2.aspmx.l.google.com"],
    "email": {
        "emailProvider": "Google Workspace",
        "spfRecord": "v=spf1 a mx include:_spf.google.com include:mailgun.org include:amazonses.com include:19497222.spf05.hubspotemail.net -all",
        "spfAll": "-all",
        "dmarcRecord": "v=DMARC1; p=reject; sp=reject; pct=100; rua=mailto:dmarc-reports@apify.com; ri=604800",
        "dmarcPolicy": "reject",
        "dmarcReportingEnabled": true,
        "dkimSelectorsFound": ["google"],
        "mtaSts": true,
        "tlsRpt": true,
        "score": 100,
        "grade": "A",
        "issues": []
    },
    "ssl": {
        "host": "apify.com",
        "reachable": true,
        "valid": true,
        "issuer": "Amazon",
        "subject": "*.apify.com",
        "validFrom": "2026-07-03T00:00:00Z",
        "validTo": "2027-01-16T23:59:59Z",
        "daysUntilExpiry": 116,
        "sanCount": 4,
        "tlsVersion": "TLSv1.3"
    },
    "issues": [],
    "processingTimeMs": 279,
    "error": null
}
```

For a domain that is not registered you get `"registered": false` and the issue
`"Domain is not registered (available)"`.

### Pricing

Pay per event: **$0.003 per domain analyzed** ($3 per 1,000 domains) - registration, DNS, SSL and
email security all included. Invalid inputs and domains where every lookup failed are free.

Worked examples:

- Enrich 5,000 lead domains = **$15**
- Monitor a 200-domain portfolio every day for a month = 6,000 lookups = **$18**
- The default demo run (3 domains) = **$0.009**

Set **Maximum cost per run** and the actor stops cleanly when it is reached.

### FAQ

**Why RDAP and not WHOIS?** RDAP is ICANN's official, structured replacement for WHOIS and is
mandatory for all generic TLDs. For country TLDs without RDAP the actor falls back to classic WHOIS
(port 43), so fields may be sparser there (for example `.de` only publishes the status).

**Why is `registrar` sometimes the company itself?** Some registries (for example Nominet for
`.uk`) list large organisations that act as their own registrar.

**How is the email grade calculated?** MX 10 points, SPF up to 25 (strict `-all` / `~all`), DMARC up
to 35 (`reject` 35, `quarantine` 28, `none` 12), DKIM 20, MTA-STS 5, TLS-RPT 5. A >= 85, B >= 70,
C >= 50, D >= 30, else F.

**Can I pass subdomains?** Yes. Registration and DNS are reported for the registrable domain, and
the SSL certificate is checked on the exact host you entered.

**Something is not working?** Open an issue on the Issues tab - it is answered quickly.

# Actor input Schema

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

Domains, website URLs or email addresses, one per line. `https://www.shop.example.co.uk/page` and `jane@example.com` are reduced to the registrable domain automatically; duplicates are removed.

## `includeWhois` (type: `boolean`):

Registrar, creation/expiry/update dates, domain age, status codes, DNSSEC and whether the domain is registered at all. Uses the official RDAP protocol, with classic WHOIS as a fallback.

## `includeDns` (type: `boolean`):

A, AAAA, MX, NS, TXT, CAA, SOA and the www host.

## `includeSsl` (type: `boolean`):

Connects on port 443 and reports certificate validity, issuer, expiry date, days left, SANs and TLS version.

## `includeEmailSecurity` (type: `boolean`):

SPF, DMARC policy, DKIM on common selectors, MTA-STS, TLS-RPT, BIMI, detected email provider, a 0-100 score, A-F grade and a list of issues.

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

How many domains are processed at the same time.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "github.com",
    "bbc.co.uk"
  ],
  "includeWhois": true,
  "includeDns": true,
  "includeSsl": true,
  "includeEmailSecurity": 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",
        "bbc.co.uk"
    ]
};

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

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

```

## MCP server setup

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