Domain WHOIS & DNS Lookup: Expiry, Registrar, MX & SPF
Pricing
from $1.50 / 1,000 domains
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
14 days ago
Last modified
Categories
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);
.comruns at about 2 domains per second. - Monitoring built in:
onlyChangesemits only domains whose registrar, expiry, nameservers, MX, SPF or DMARC changed;expiringWithinDaysfinds 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: falseresult.
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.
| Option | Default | Meaning |
|---|---|---|
checks | ["registry", "dns"] | registry (RDAP/WHOIS), dns, or both. Unknown values are ignored. |
onlyChanges | false | Emit new domains or changes to monitored fields. |
previousDatasetId | omitted | Read-only dataset for the comparison baseline. |
expiringWithinDays | unset | Emit domains expiring within N days, including expired domains; unknown expiry is excluded. |
maxDomains | unset | Limit 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
| Event | Price |
|---|---|
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.
| Hosts | Requests/s per host |
|---|---|
cloudflare-dns.com, dns.google | 10 |
rdap.verisign.com, pubapi.registry.google | 2 |
rdap.publicinterestregistry.org, rdap.identitydigital.services, rdap.nominet.uk, rdap.nic.fr, rdap.sidn.nl, rdap.registro.br, rdap.cctld.au, rdap.ca.fury.ca | 1 |
rdap.denic.de, rdap.nic.ch | 0.5 |
| Other RDAP hosts | 1 |
data.iana.org | One 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
| Coverage | TLDs (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: falsecomes 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.