Bulk WHOIS Lookup & DNS Lookup - Domain Age & Expiry
Pricing
from $1.60 / 1,000 domain looked ups
Bulk WHOIS Lookup & DNS Lookup - Domain Age & Expiry
Look up many domains at once: registrar, creation and expiry dates, status and name servers via RDAP (WHOIS fallback), availability, A/MX/NS/TXT/CAA records, SPF/DMARC grade. $2/1,000.
Pricing
from $1.60 / 1,000 domain looked ups
Rating
0.0
(0)
Developer
Yukai Lin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
What does Bulk WHOIS & DNS Lookup do?
Bulk WHOIS and DNS lookup: give it a list of domains, URLs or e-mail addresses and get the registrar, creation and expiry dates (domain age), availability and DNS records for each domain. In detail, each domain gets:
- 📅 Registration data (WHOIS): registrar and IANA ID, creation, update and expiry dates, days to expiry, domain age, status codes (e.g.
clientTransferProhibited), name servers, DNSSEC, and the registrant organization and country when the registry or registrar publishes them - 🌐 DNS records: A, AAAA, MX, NS, TXT and CAA, the CNAME of
www, and the_dmarcrecord - ✉️ E-mail security grade (A-F): SPF policy (
-all,~all...), DMARC policy (reject,quarantine,none), MX present, plus a list of issues (no SPF, two SPF records,p=none, more than 10 SPF lookups...) - 🔎 Availability guess (optional):
registered,likely_availableorunknown, always worded as a guess
Registration data comes from RDAP, the official JSON successor of WHOIS: the Actor finds each registry's RDAP server through the IANA bootstrap file (with https://rdap.org as a fallback). Country-code TLDs without RDAP (.jp, .io, .co, .it, .eu, .ru, .cn...) are asked over classic WHOIS (port 43) instead. DNS is read over DNS-over-HTTPS (Cloudflare, Google as a fallback).
Inputs are reduced to the registrable domain (https://www.bbc.co.uk/news → bbc.co.uk, jane@shop.example.de → example.de, _dmarc.github.com → github.com), and the same domain is looked up and charged once.
Use cases
- Domain portfolio monitoring: find domains that expire soon (
daysToExpiry) or lost their transfer lock - Lead research and enrichment: domain age, registrant company and country, mail provider (from MX)
- E-mail deliverability and security audits: SPF / DMARC / MX for hundreds of client domains at once
- Brand protection: check look-alike domains and who registered them
- Domain hunting: a first pass over name ideas with the availability guess, before checking at a registrar
- AI agents: "When does this domain expire and who hosts its mail?"
How much does it cost?
| Event | Price |
|---|---|
| Domain looked up | $2.00 / 1,000 domains |
Example: 10,000 domains cost 10,000 × $0.002 = $20.00 on the Free plan.
No start fee. Higher Apify plans get volume discounts (see the Pricing tab). A domain is charged when registration data or DNS records were returned. Invalid inputs and lookups where both RDAP/WHOIS and DNS failed, or where registration data could not be read and the name does not resolve in DNS either (e.g. a TLD that does not exist) are not charged; they carry an errorType. A domain the registry says does not exist is a valid answer ("not registered") and is charged.
Control your cost
- Before anything is looked up, the run logs its plan: the number of unique domains × the price = the most the run can cost, compared with your maximum charge per run.
- Charged: a domain for which registration data or DNS records were returned ($0.002). Every row has
charged: trueorfalse. - Free: lookups where both RDAP/WHOIS and DNS failed, or where registration data could not be read and the name does not resolve in DNS either (e.g. a TLD that does not exist), invalid lines (one row per line, e.g.
not a domain, IP addresses), and duplicates (github.com,www.github.comandjane@github.comare one domain). - No plan limits: there is no cap on how many domains a free Apify user can look up; only your maximum charge per run (run options or
maxTotalChargeUsd) stops a run. When the next domain could exceed it, no new domain is started; the run ends with statusLIMIT_REACHED, and theSUMMARYrecord lists the domains not processed (notProcessed: the count and up to 100 inputs). - If Apify restarts the run (server migration or Resurrect), items already finished are skipped and not charged again (
SUMMARY.resumedSkipped).
Price comparison (checked September 2026)
| Actor | Price | Notes |
|---|---|---|
| Bulk Domain WHOIS (RDAP) & DNS Lookup (this Actor) | $0.002 per domain, no start fee | WHOIS + DNS + SPF/DMARC grade in one row |
| ntriqpro/whois-domain-lookup | $0.02 per domain | |
| santamaria-automations/domain-whois-dns | pay per event; we recorded only its $0.001 start event | |
| agenscrape/whois-domain-lookup | pay per event, price not recorded in our check | |
| onescales/domain-availability-checker | free | availability only |
How to use it
- Paste your domains (or URLs, or e-mail addresses), one per line, or pick another run's Dataset ID and the Dataset field with the domain, URL or e-mail (e.g. the output of a contact or lead scraper). Several entries on one line may be separated by commas; a line that is not a domain (e.g. a company name) stays one
invalid_inputrow and is not charged. - Keep Registration data and DNS records on, or turn one off if you only need the other.
- Optional: turn on Guess availability.
- Click Start and export the results as JSON, CSV or Excel. The DNS & e-mail security view shows the DNS columns.
Input example
This is the input the form is prefilled with; a run with it takes about a minute and costs only cents:
{"domains": ["github.com","https://www.bbc.co.uk/news","spiegel.de","sony.jp"]}
Output example (real result, September 2026)
github.com and www.github.com were both in the input, so they became one row (inputs). TXT records are shortened here.
{"input": "github.com","inputs": ["github.com", "www.github.com"],"domain": "github.com","tld": "com","success": true,"registered": true,"registrar": "MarkMonitor Inc.","registrarIanaId": "292","createdAt": "2007-10-09T18:20:50Z","updatedAt": "2026-09-07T09:22:52Z","expiresAt": "2028-10-09T18:20:50Z","daysToExpiry": 741,"domainAgeDays": 6930,"status": ["clientDeleteProhibited", "clientTransferProhibited", "clientUpdateProhibited"],"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,"registrantOrg": "GitHub, Inc.","registrantCountry": "US","registrationSource": "rdap","registrationServer": "rdap.verisign.com","availability": "registered","dnsResolves": true,"dns": {"a": ["140.82.112.4"],"aaaa": [],"mx": [{ "priority": 0, "host": "github-com.mail.protection.outlook.com" }],"ns": ["dns1.p08.nsone.net", "..."],"txt": ["MS=ms44452932", "google-site-verification=…", "v=spf1 ip4:192.30.252.0/22 include:spf.protection.outlook.com … ~all"],"caa": [{ "flags": 0, "tag": "issue", "value": "digicert.com" }, { "flags": 0, "tag": "issue", "value": "letsencrypt.org" }, "..."],"wwwCname": "github.com","dmarc": "v=DMARC1; p=quarantine; sp=reject; pct=100; rua=mailto:dmarc@github.com; ruf=mailto:dmarc@github.com; fo=1"},"emailSecurity": {"grade": "B","hasMx": true,"spfPolicy": "softfail","dmarcPolicy": "quarantine","spf": { "policy": "softfail", "includes": ["spf.protection.outlook.com", "_netblocks.google.com", "..."], "dnsLookups": 8, "multipleRecords": false },"dmarc": { "policy": "quarantine", "subdomainPolicy": "reject", "pct": 100, "rua": ["mailto:dmarc@github.com"] },"issues": [],"note": "DKIM is not checked (it needs the sender's selector)."},"emailGrade": "B","checkedAt": "2026-09-29T14:16:25.456Z"}
A name nobody has registered, with Guess availability on:
{ "domain": "this-domain-surely-not-registered-xyz123.com", "success": true, "registered": false, "availability": "likely_available","availabilityNote": "Guess: the registry has no record of this domain. Premium, reserved or blocked names can still be unavailable; confirm with a registrar.","registrationSource": "rdap", "registrationServer": "rdap.verisign.com", "dnsResolves": false }
E-mail grades: A = SPF (-all/~all) and DMARC p=reject; B = DMARC p=quarantine (or reject for part of the mail, or in testing mode t=y from DMARCbis, RFC 9989; testing and nonExistentSubdomainPolicy (np=) are in dmarc); C = DMARC p=none; D = only SPF or only DMARC, or a weak SPF (?all, +all); F = neither. Domains with no MX that publish v=spf1 -all and DMARC reject get A (they are locked against spoofing). SPF redirect= and include: are followed like a mail server does (RFC 7208, at most 10 DNS lookups): a record such as v=spf1 redirect=_spf.example.com takes the policy of the target record (spfRedirect, spfDnsLookups). Every grade below A comes with at least one entry in issues.
A SUMMARY record in the key-value store has the run status (SUCCESS, PARTIAL_RESULTS, FAILED, NO_RESULTS, LIMIT_REACHED), failures by errorType, where registration data came from (rdap / whois), the count of each e-mail grade and the number of invalid lines. Each row has input (and inputs when several lines were the same domain) and inputIndex; an input such as _dmarc.github.com also gets an inputNote saying which domain was looked up (DMARC is in dns.dmarc).
Coverage by TLD (our test of 20 domains, September 2026)
RDAP and WHOIS data differ by registry. What we got:
| TLD | Source | What the registry returned |
|---|---|---|
| .com, .net, .org, .dev, .app, .fr | RDAP | Full: registrar, dates, status, name servers; registrant org/country when public |
| .co.uk (Nominet) | RDAP | Registrar, dates, status, name servers |
| .kr | RDAP | Dates, status, name servers (no registrar name) |
| .com.au | RDAP | Registrar, status, name servers; no creation or expiry dates (not published) |
| .de (DENIC) | RDAP | Status and name servers only; DENIC publishes no dates, registrar or holder |
| .ch | RDAP | Registrar, status, name servers; no dates |
| .io, .co | WHOIS | Full, including registrant org and country when public |
| .jp | WHOIS | Dates, registrant, name servers; no registrar. For .co.jp, .ac.jp and other organisation-type names the expiry date comes from [State]; JPRS leaves the registration date blank for some names registered before its database (e.g. toyota.co.jp), so createdAt is then null |
| .it | WHOIS | Registrar, dates, registrant org, name servers |
| .ru | WHOIS | Registrar, creation and paid-till dates, name servers |
| .com.tw | WHOIS | Registrar, dates, registrant, name servers (the TWNIC RDAP server answered HTTP 426 in our test, so WHOIS is used) |
| .eu | WHOIS | Registrar and name servers only; EURid publishes no dates |
| .cn | WHOIS | Worked from our computer, but CNNIC's WHOIS server timed out from Apify's network in our test |
| .es | — | No RDAP, and the .es WHOIS server only answers pre-registered IP addresses: no registration data (DNS still works) |
When registration data cannot be read, the row still has the DNS records plus registrationError; registered is then null.
Use with AI agents (MCP)
Connect Apify's MCP server (https://mcp.apify.com?tools=tidytools/bulk-domain-whois-dns-lookup) to Claude, Cursor or any MCP client, then ask e.g. "Which of these 50 domains expire in the next 90 days, and which have no DMARC record?"
{ "domains": ["github.com", "example.co.uk"] }
Failed lookups and invalid lines are not charged and carry an errorType.
Use it from code
curl -X POST "https://api.apify.com/v2/acts/tidytools~bulk-domain-whois-dns-lookup/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"domains":["github.com","bbc.co.uk"],"checkAvailability":true}'
Schedules and integrations: run it daily or weekly with Apify Schedules, get a webhook when a run finishes, or send the results to Zapier, Make, n8n, Google Sheets, Slack and other apps with Apify integrations. Results can be exported as JSON, CSV, Excel or XML.
Advanced settings
- WHOIS fallback for TLDs without RDAP (on by default): ask the registry's port-43 WHOIS server when a TLD has no RDAP server or its RDAP server fails.
- Ask the registrar's RDAP server for registrant details (on by default): .com and .net registries keep only basic data; the registrant organization and country come from the registrar's RDAP server (one extra request).
- Proxy: optional Apify Proxy for RDAP and DNS-over-HTTPS requests (not for port-43 WHOIS), billed to your Apify account.
- Parallel domains: requests to one registry are limited to 4 at a time to avoid rate limits.
Limitations
- Registrable domain rule: the last two labels, or the last three when the last two are a known second-level suffix (
co.uk,com.au,co.jp,com.tw...) or a two-letter country TLD with a generic second level (co,com,net,org,gov,edu,ac,or,ne,go). This is a documented simple rule, not the full Public Suffix List; a two-label name such asgo.toorco.ccis looked up as it is, only the listed suffixes (co.uk,com.au...) alone are rejected. Hosting suffixes such asgithub.ioare not treated as suffixes:user.github.io→github.io, the name that is registered. - Privacy: most registrant names and e-mails are redacted under GDPR. Values that say "REDACTED", "privacy", "on behalf of" and similar are returned as
null, but some privacy services use an ordinary-looking company name. - Availability is a guess.
likely_availablemeans the registry has no record. Premium, reserved and blocked names can still be unavailable. - WHOIS text formats differ per registry; the parser reads the common field names. Dates are returned in UTC; registries that give a local time without a zone are read as UTC.
- DKIM is not checked (it needs the sender's selector). DNS answers come from public resolvers, so very recent changes may not be visible yet.
Responsible use
- Only the registrant organisation and country are returned, and only when the registry publishes them. The name, email and phone of an individual registrant, and admin/tech/billing contacts, are never returned: a bare "Registrant:" line in a WHOIS answer (e.g. .cn, .tw) is kept only when it reads like an organisation (Inc, Ltd, GmbH, 公司 …), because it could be a private person.
- Registration data is public registry data (WHOIS/RDAP); follow the registries' terms and the data-protection laws that apply to you.
FAQ
Does the Actor collect usage data? The Actor sends one anonymous usage counter per run (input type, item count range, outcome) to improve the tool; no URLs, content or account data.
Is this a WHOIS lookup or an RDAP lookup? Both. Registration data comes from RDAP, the official JSON successor of WHOIS, found through the IANA bootstrap file (with rdap.org as a fallback). Country-code TLDs without RDAP (.jp, .io, .co, .it, .eu, .ru, .cn...) are asked over classic WHOIS (port 43) when WHOIS fallback for TLDs without RDAP is on, which it is by default.
Does it show domain age, expiry dates and DNS records? Yes. Each domain gets creation, update and expiry dates, days to expiry and domain age, plus DNS records (A, AAAA, MX, NS, TXT, CAA, the CNAME of www and the _dmarc record) read over DNS-over-HTTPS. Turn off Registration data (WHOIS / RDAP) or DNS records if you only need the other; some registries (e.g. .de, .eu, .ch, .com.au) publish no dates.
Can it check domain availability? Turn on Guess availability to get registered, likely_available or unknown for each domain. It is always a guess: likely_available means the registry itself answered that it has no record, but premium, reserved or blocked names can still be unavailable, so confirm with a registrar. When the registry could not be reached and only rdap.org answered "not found", or a registry's WHOIS server timed out, the domain is unknown, never likely_available.
What is charged and what is free? You pay $2.00 per 1,000 domains with no start fee, charged when registration data or DNS records were returned (a registry answer that the domain does not exist also counts). Lookups where both RDAP/WHOIS and DNS failed, or where registration data could not be read and the name does not resolve in DNS either (e.g. a TLD that does not exist), invalid lines and duplicates (github.com, www.github.com and jane@github.com are one domain) are free.
What if my input is empty, or has only invalid lines? The run ends normally (it does not fail): each invalid line gets a free invalid_input row, an empty input or both Registration data and DNS records switched off gets one such row, SUMMARY.status is NO_RESULTS and nothing is charged. A dataset ID that cannot be read gets the same kind of free row, and the other domains of the run are still looked up.
Why is a domain I gave marked not_found and free? Registration data was asked for and could not be read (e.g. the TLD does not exist or has no WHOIS), and the name does not resolve in DNS either, so there was nothing to return.
Can I give non-Latin (IDN) domains, quoted or pasted text? Yes. bücher.de or 台灣.tw are converted to punycode (xn--bcher-kva.de) and the row's domain holds that ASCII form; input keeps what you typed. Quotes, angle brackets and a trailing ; or ) around a name are ignored.
What do the errorType values mean? invalid_input (not a domain, IP address, a registry suffix such as co.uk, empty input), not_found (no registration data and the name does not resolve), no_registration_data (the TLD has no RDAP or WHOIS service and DNS was off), network (registry unreachable), blocked (the registry's WHOIS server refuses automated queries), timeout, save_failed. All of them are free.
Related Actors
More tools by TidyTools that work well with this one:
- Website Tech Stack Detector: find the CMS, shop platform and tools a site uses
- Company Website Enrichment: add company details to a list of domains
- Email List Cleaner: clean an email list with MX, disposable and typo checks
- Bulk URL Status Checker: check HTTP status and redirects for a list of URLs
Support
Open an issue in the Issues tab with the domain. Issues are checked regularly.
Found this useful? A short review on the Store helps other users find it.