Domain WHOIS & DNS Lookup: Expiry, Registrar, MX & SPF avatar

Domain WHOIS & DNS Lookup: Expiry, Registrar, MX & SPF

Pricing

from $1.50 / 1,000 domains

Go to Apify Store
Domain WHOIS & DNS Lookup: Expiry, Registrar, MX & SPF

Domain WHOIS & DNS Lookup: Expiry, Registrar, MX & SPF

WHOIS + DNS in one: expiry, registrar, MX provider, SPF and DMARC. Monitor changes and expiring domains. $1.50 per 1,000 emitted domains; unreadable domains are free.

Pricing

from $1.50 / 1,000 domains

Rating

0.0

(0)

Developer

pfistyle.digital

pfistyle.digital

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

14 days ago

Last modified

Share

$1.50 per 1,000 domains, WHOIS + DNS in one run. Get registration date, expiry, registrar, nameservers, DNSSEC, IP addresses, email provider (MX), SPF and DMARC as flat rows, ready for spreadsheets, APIs and AI agents. Unreadable domains, unchanged domains and filtered results are free.

  • Fast: 11 mixed domains in under 6 seconds (measured 2026-10-09); .com runs at about 2 domains per second.
  • Monitoring built in: onlyChanges emits only domains whose registrar, expiry, nameservers, MX, SPF or DMARC changed; expiringWithinDays finds domains about to expire.
  • Privacy-safe: registrar company only, never registrant or admin contact data.
  • Official sources: RDAP (the ICANN successor to WHOIS) and public DNS over HTTPS. No browser, no proxy.

Use cases

  • Enrich company leads with their domain age and email provider.
  • Monitor a domain portfolio for registry changes and upcoming expiry.
  • Check SPF and DMARC policies and identify young domains for security or KYB reviews.
  • Check availability: a registry 404 is an explicit registered: false result.

Input

{
"domains": ["apify.com", "github.com", "bbc.co.uk"],
"checks": ["registry", "dns"]
}

domains accepts a list or text separated by newlines, commas or semicolons. Domain names, URLs (https://www.apify.com/pricing), email addresses (info@apify.com), uppercase, trailing dots and IDNs (müller.de) work. Subdomains reduce to their registrable domain using the ICANN Public Suffix List: news.bbc.co.uk becomes bbc.co.uk. Duplicate normalized domains are removed; the first original input is retained. Invalid entries are skipped individually.

OptionDefaultMeaning
checks["registry", "dns"]registry (RDAP/WHOIS), dns, or both. Unknown values are ignored.
onlyChangesfalseEmit new domains or changes to monitored fields.
previousDatasetIdomittedRead-only dataset for the comparison baseline.
expiringWithinDaysunsetEmit domains expiring within N days, including expired domains; unknown expiry is excluded.
maxDomainsunsetLimit unique valid domains after normalization.

Empty input fails with a useful message. Individual invalid or unreadable domains do not stop the other lookups.

Output

One flat row per emitted domain, with comma-separated lists. Real output for apify.com (2026-10-09):

{
"domain": "apify.com",
"input": "https://www.apify.com/pricing",
"registered": true,
"tld": "com",
"registrar": "Amazon Registrar, Inc.",
"registrarIanaId": "468",
"registeredAt": "2009-06-02",
"expiresAt": "2035-06-02",
"updatedAt": "2026-05-16",
"ageDays": 6338,
"daysUntilExpiry": 3158,
"status": "client transfer prohibited",
"nameservers": "ns-1225.awsdns-25.org, ns-1928.awsdns-49.co.uk, ns-449.awsdns-56.com, ns-839.awsdns-40.net",
"dnssec": true,
"a": "143.204.55.100, 143.204.55.60, 143.204.55.7, 143.204.55.88",
"aaaa": "2600:9000:20a5:400:9:a03e:6540:93a1, 2600:9000:20a5:4200:9:a03e:6540:93a1, 2600:9000:20a5:4c00:9:a03e:6540:93a1, 2600:9000:20a5:5200:9:a03e:6540:93a1, 2600:9000:20a5:6200:9:a03e:6540:93a1, 2600:9000:20a5:ae00:9:a03e:6540:93a1, 2600:9000:20a5:d400:9:a03e:6540:93a1, 2600:9000:20a5:fa00:9:a03e:6540:93a1",
"mx": "1 aspmx.l.google.com, 5 alt1.aspmx.l.google.com, 5 alt2.aspmx.l.google.com, 10 aspmx2.googlemail.com, 10 aspmx3.googlemail.com",
"mailProvider": "google",
"spf": "v=spf1 a mx include:_spf.google.com include:mailgun.org include:amazonses.com include:19497222.spf05.hubspotemail.net -all",
"dmarcPolicy": "reject",
"registrySource": "https://rdap.verisign.com/com/v1/",
"registryNote": null,
"checkedAt": "2026-10-09T14:35:28.132063Z",
"changedFields": null
}

Dates are YYYY-MM-DD; checkedAt is UTC. Unknown fields are null. registered is true for a registry domain response or positive DNS answer, false for registry 404 or DNS NXDOMAIN without a registry result, and null when unclear. Registry results take precedence over DNS. NXDOMAIN for _dmarc alone does not mean the domain is available. DNS availability does not prove that a domain can be purchased.

mailProvider is one of google, microsoft, zoho, proton, yandex, amazon-ses, mimecast, proofpoint, ovh, ionos, other, none. MX priorities are retained and sorted numerically. spf is the whole SPF TXT record; dmarcPolicy is none, quarantine, reject, or null. registryNote is null, no_rdap, limited_registry_data, or rdap_error. changedFields is populated only when onlyChanges is enabled.

Pricing

EventPrice
domain: one emitted row$0.0015
Actor start, per GB of memory (minimum one event)$0.00005

You pay only these events; platform usage is included. A row is charged if at least one requested check returned a result, including confirmed availability. Partial readable results are charged once. Invalid domains, duplicates, all-failed lookups, unchanged rows, expiry-filtered rows and domains beyond the configured limit have no domain charge. The cost limit is checked before every charge; the run stops cleanly when your limit is reached.

Scheduled monitoring

Create an Apify Schedule, for example daily, and select a previous dataset:

{
"domains": ["apify.com", "github.com"],
"checks": ["registry", "dns"],
"onlyChanges": true,
"expiringWithinDays": 30,
"previousDatasetId": "PREVIOUS_DATASET_ID"
}

Set previousDatasetId to the last run's dataset ID (select it with the dataset picker). The selected dataset is only read and is never modified. Missing, invalid or inaccessible datasets produce a log warning and a comparisonNotice in SUMMARY; the run continues with duplicate suppression within the current run. Without a previous dataset, every distinct current row is eligible for output. No persistent history is maintained. A dataset containing only new/changed rows, a filtered result or a cost-interrupted result is an incomplete baseline: rows absent from it can be emitted again. For reliable repeated monitoring, compare with a complete snapshot dataset and update the input through your scheduler or integration; a static schedule does not automatically select the last run.

Domains are matched by normalized domain. Compared fields are registered, registrar, expiresAt, status, nameservers, dnssec, mx, spf and dmarcPolicy; A/AAAA and daily counters are excluded. comparisonFields and comparisonHash preserve the effective comparison snapshot, including known values retained after partial failures. Existing datasets without these fields are reconstructed from the output fields. Disable onlyChanges for recurring expiry reminders.

Use with AI agents / MCP

https://mcp.apify.com?tools=pfistyle.digital/domain-whois-dns

Example prompt: "Use pfistyle.digital/domain-whois-dns to check the registrar, expiry, email provider and DMARC policy for apify.com and github.com."

Direct API call:

curl -X POST "https://api.apify.com/v2/acts/pfistyle.digital~domain-whois-dns/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
-d '{"domains":["apify.com","github.com"],"checks":["registry","dns"]}'

How it works

The actor downloads the IANA RDAP bootstrap once per registry-enabled run, falling back to the bundled copy. It adds DENIC (.de), SWITCH (.ch/.li) and Identity Digital (.io). RDAP is the public successor to WHOIS. DNS uses Cloudflare JSON DNS over HTTPS, switching to Google after three consecutive resolver failures and retaining the selected resolver for later queries. It requests A, AAAA, MX, TXT and _dmarc TXT; NS is queried only when RDAP supplied none.

Eight domain workers share thread-safe per-host rate limits. RDAP requests have a 30-second timeout and up to three retries with 2/4/8-second backoff for 429, 5xx and connection failures. RDAP 429 honors Retry-After seconds or an HTTP date, capped at 60 seconds, and halves that host's limit for the rest of the run (floor 0.2 requests/s). The cooldown applies across workers. DoH backs off on transport and resolver failures and switches after three failures. User-Agent: DomainWhoisDnsReader/0.1.

HostsRequests/s per host
cloudflare-dns.com, dns.google10
rdap.verisign.com, pubapi.registry.google2
rdap.publicinterestregistry.org, rdap.identitydigital.services, rdap.nominet.uk, rdap.nic.fr, rdap.sidn.nl, rdap.registro.br, rdap.cctld.au, rdap.ca.fury.ca1
rdap.denic.de, rdap.nic.ch0.5
Other RDAP hosts1
data.iana.orgOne bootstrap request per run

The Public Suffix List (ICANN section, MPL-2.0) and a copy of the IANA RDAP bootstrap are bundled. Private suffixes are excluded: blog.github.io becomes github.io.

Which TLDs work

CoverageTLDs (tested 2026-10-09)
Full registry data + DNS.com, .net, .org, .io, .ai, .uk (incl. .co.uk), .fr, .nl, .app, .dev, .ca, .au, .br, .in and every other TLD listed in the IANA RDAP bootstrap (1,200+, all generic TLDs)
Limited registry data + DNS.de, .ch, .li (registration status and nameservers, usually no registrar or expiry)
DNS only.co, .eu, .it, .es, .us, .at, .jp, .cn, .ru and other TLDs without RDAP (registryNote: "no_rdap")

Known limitations

  • What works: registrar, dates, status, nameservers and DNSSEC for all RDAP TLDs; A, AAAA, MX, SPF and DMARC for every TLD.
  • Registrant, administrative, technical and billing contacts are never returned, by design.
  • .de and .ch/.li registries publish no expiry or registrar; DNS-only TLDs have no registry dates. There is no port-43 WHOIS fallback yet.
  • registered: false comes from a registry 404 or DNS NXDOMAIN; it does not guarantee the domain can be bought (premium or reserved names).
  • SPF and DMARC are reported as published, not validated as a full email-security audit.

Unreadable domains are free

Every run writes SUMMARY to its default key-value store. It contains counters input, valid, output, charged, registered, notRegistered, unchanged, notExpiring, checked; no_rdap counters by TLD; rateLimited counters by host; and skipped entries with domain, reason, detail. Reasons: invalid_domain, lookup_failed, cost_limit, domain_limit, unchanged, not_expiring. Registered/available counters describe checked domains, including those filtered from output; valid counts unique normalized domains before maxDomains.

Example SUMMARY:

{"input": 3, "valid": 3, "output": 3, "charged": 3, "registered": 3, "notRegistered": 0, "unchanged": 0, "notExpiring": 0, "checked": 3, "skipped": [], "no_rdap": {}, "rateLimited": {}}

Status line: 3 domains delivered, 3 checked (3 registered, 0 available); skipped, not charged: 0 invalid, 0 failed; with filters or a cost limit it adds e.g. , 3 unchanged or ; stopped at cost limit, 7 not processed. A domain where no requested check returned a result produces no row and no charge; other domains continue.