Website Tech Stack Lookup - Technology Detector
Detect the technology stack of any list of domains: CMS, ecommerce, analytics, CDN, frameworks with versions, plus mail provider, SPF and DMARC.
datagrit › Data › Domain WHOIS RDAP Lookup - DNS, MX & Expiry
DataBulk domain lookup: official RDAP (WHOIS) registration, expiry and availability plus DNS, mail provider, SPF/DMARC and hosting ASN, with expiry and registrar filters.
Domain WHOIS RDAP Lookup takes a list of domains and returns one flat row per domain: official registration data from the registry's RDAP server (the structured successor of WHOIS) plus the domain's DNS, mail provider, SPF and DMARC policy, and hosting network. It is built for bulk work: SEO and domain investors checking age and expiry, sales teams enriching lead lists with mail stack data, and security teams auditing email authentication.
Registrar name, IANA registrar id and abuse e-mail, creation, last change and expiry dates, domain age and days to expiry, EPP status codes with transferLocked and deletionPending flags, registry nameservers and DNSSEC. Registrant organization and country only when the registry or registrar publishes them; redacted values become null with registrantRedacted: true. When the registrant card is a privacy or proxy service (Domains By Proxy, Withheld for Privacy and similar), the country is null too, because the address on the card is the service's. Personal names, addresses, e-mails and phone numbers are never returned.
registered: false means the registry's RDAP server answered "not found" and the name is not delegated in DNS. When RDAP says not found but DNS still delegates the name, the row is found: false with reason notFoundButDelegated instead of a false "available"; when the delegation check itself fails, the row is found: false with reason dnsUnavailable. Both are free.
A, AAAA, MX, NS and TXT records, mail provider (Google Workspace, Microsoft 365, Zoho, Proton, Fastmail, Amazon SES and 25 more), security gateway (Mimecast, Proofpoint, Broadcom, Barracuda, Cisco and others, with the mailbox provider behind it taken from the SPF include), DNS provider, SPF record and its all-mechanism, DMARC record and policy, DKIM keys on 9 common selectors, and the hosting ASN, network name and country of the first IPv4 address.
The RDAP server for each TLD comes from the IANA RDAP bootstrap file. Seven registries run official RDAP servers that are not in that file yet (.io, .sh, .ac, .me, .us, .ch, .li); they are used directly. If the IANA file cannot be read, lookups go through rdap.org. TLDs with no RDAP server in the IANA file or in that verified list (for example .de, .co, .it, .eu, .jp) are returned as found: false with reason noRdapService, free, and listed in the run status.
Requests are paced per server. Measured on 2026-10-01: Verisign (.com) answered 30 requests at up to 15 per second without a limit response; the Actor sends at most 10 per second and 4 in parallel to one registry. GoDaddy's registrar RDAP allows 6 requests per minute and answers 429 with Retry-After; the Actor waits as asked (up to 3 minutes). When a server reports x-ratelimit-remaining: 0, the Actor pauses that server until x-ratelimit-reset, or for 60 seconds when no reset time is sent.
Every result is one flat record, so it drops straight into a spreadsheet, a database or a CRM.
| Field | Type | Description | Example |
|---|---|---|---|
input | string | The entry from your input that produced this row. Null only on the "no match" status row. | https://www.wikipedia.org/wiki/Domain |
domain | string | Registered domain that was looked up, lowercase ASCII (IDN names in punycode). Subdomains and URLs are reduced to it. | wikipedia.org |
tld | string | Top-level domain (last label) used to find the RDAP server. | org |
found | boolean | true when the registry gave a definitive answer (registered or not registered); false on rows that could not be looked up (see reason). found:false rows are free. | true |
registered | boolean | true = the registry holds a registration; false = RDAP answered not found and the name is not delegated in DNS (available, unless the registry reserves it); null = unknown (found:false). | true |
reason | string | Why the row has no answer: noRdapService (no RDAP server is known for the TLD: not in the IANA bootstrap nor in the verified list, e.g. .de), rateLimited, rdapError, rejectedByRegistry (the registry refused the name), unexpectedResponse, notFoundButDelegated (RDAP says not found but DNS delegates the name), dnsUnavailable (RDAP says not found but the DNS delegation check failed, so availability is not confirmed), noMatch (no domain passed your filters). Null on answered rows. | |
registrar | string | Sponsoring registrar name as published by the registry (for .uk the Nominet tag holder). | MarkMonitor Inc. |
registrarIanaId | integer | IANA Registrar ID of the sponsoring registrar; null when the registry publishes none (many ccTLDs). | 292 |
registrarAbuseEmail | string | Abuse contact e-mail of the registrar from the registry record (or from the registrar RDAP record when that lookup is on and the registry has none). | abusecomplaints@markmonitor.com |
createdAt | string | Registration date (RDAP event "registration"), ISO 8601 UTC. | 2001-01-13T00:12:14.754Z |
updatedAt | string | Last change of the registry record (RDAP event "last changed"), ISO 8601 UTC. | 2026-08-12T08:47:19.410Z |
expiresAt | string | Registry expiry date (RDAP event "expiration"), ISO 8601 UTC. Null when the registry does not publish it (for example .ch and .li). | 2027-01-13T00:12:14.000Z |
domainAgeDays | integer | Whole days since createdAt at the time of the run. | 9391 |
daysToExpiry | integer | Whole days from the run to expiresAt; negative when the date has passed and the registry still holds the domain. | 104 |
status | array | Registry status codes converted from RDAP wording to EPP names, for example clientTransferProhibited, redemptionPeriod, pendingDelete; RDAP "active" becomes ok. | ["clientDeleteProhibited","clientTransferProhibited","c |
transferLocked | boolean | true when status contains clientTransferProhibited or serverTransferProhibited. | true |
deletionPending | boolean | true when status contains redemptionPeriod, pendingDelete or pendingRestore (the domain is on its way to being released). | false |
nameservers | array | Nameservers delegated at the registry, lowercase, sorted. | ["ns0.wikimedia.org","ns1.wikimedia.org","ns2.wikimedia |
dnssec | boolean | Whether the delegation is DNSSEC-signed (RDAP secureDNS.delegationSigned); null when the registry does not say. | false |
registrantOrganization | string | Registrant organization when the registry (or the registrar, with Registrant from registrar RDAP) publishes it. Null when redacted, when a privacy or proxy service is shown instead, or when no registrant data is published. Personal names, addresses, e-mails and phone numbers are never returned. | Wikimedia Foundation, Inc. |
registrantCountry | string | Two-letter country code of the registrant when published and not redacted. Null when the registrant card belongs to a privacy or proxy service (Domains By Proxy, Withheld for Privacy and similar), because its address is that of the service, not of the owner; GDPR-redacted cards that keep the real country (for example MarkMonitor, Cloudflare) keep it. | US |
registrantRedacted | boolean | true = registrant data withheld or replaced by a privacy service; false = registrant organization published; null = the record carries no registrant data (thin registries such as .com unless Registrant from registrar RDAP is on). | false |
registrarRdap | string | notNeeded (the registry record already had registrant data), off (option disabled), noLink (the registry gives no registrar RDAP link), ok, failed, rateLimited. Null on rows of unregistered or unanswered domains. | ok |
dnsStatus | string | ok (the resolver answered; empty lists mean no such records), nxdomain (the name does not exist in DNS), failed (resolver errors for every record type; list fields are then null), skipped (DNS turned off). For not-registered domains only the NS delegation is checked. | ok |
aRecords | array | IPv4 addresses of the domain apex, sorted. [] = no A record, null = lookup failed or not run. | ["103.102.166.224"] |
aaaaRecords | array | IPv6 addresses of the domain apex, sorted. [] = none, null = lookup failed or not run. | ["2001:df2:e500:ed1a::1"] |
mxRecords | array | Mail exchanger hosts ordered by priority. [] = no MX record, null = lookup failed or not run. | ["mx-in1001.wikimedia.org","mx-in2001.wikimedia.org"] |
mailProvider | string | Mailbox provider recognised from the MX hosts (Google Workspace, Microsoft 365, Zoho Mail, Proton Mail, Amazon WorkMail / SES and 25 more). When the MX points to a security gateway it is taken from the SPF include for Google, Microsoft, Zoho, Proton, Fastmail or Amazon SES if present. "Other" = MX present but not recognised; null = no MX, or a gateway with no recognisable SPF include. | Google Workspace |
mailGateway | string | Email security gateway in front of the mailboxes, recognised from the MX hosts (Mimecast, Proofpoint, Broadcom Email Security.cloud, Barracuda, Cisco Secure Email and others); null when none. | Proofpoint |
dnsNameservers | array | NS records answered by DNS for the domain, sorted; can differ from the registry list during a DNS migration. | ["ns0.wikimedia.org","ns1.wikimedia.org","ns2.wikimedia |
dnsProvider | string | Managed DNS provider recognised from the NS hosts (Cloudflare, Amazon Route 53, Google Cloud DNS, Azure DNS, GoDaddy, Namecheap and others); "Other" when not recognised. | Cloudflare |
spfRecord | string | The v=spf1 TXT record of the domain; null when absent or DNS not run. | v=spf1 include:_spf.google.com ~all |
spfPolicy | string | The final all mechanism of the SPF record: -all, ~all, ?all or +all, or redirect when the record delegates with redirect=. | ~all |
dmarcRecord | string | The v=DMARC1 TXT record at _dmarc.<domain>; null when absent or DNS not run. | v=DMARC1; p=reject; rua=mailto:dmarc-rua@wikimedia.org; |
dmarcPolicy | string | The p= tag of the DMARC record: none, quarantine or reject. | reject |
dkimSelectors | array | Which of the common selectors google, selector1, selector2, k1, s1, s2, default, dkim and mail publish a DKIM key. An empty list does not prove the domain has no DKIM: custom selectors cannot be listed. | ["google"] |
hostingIp | string | The IPv4 address used for the hosting lookup (first A record in sorted order). | 103.102.166.224 |
hostingAsn | integer | Autonomous system number announcing hostingIp (Team Cymru IP-to-ASN service). | 14907 |
hostingAsnName | string | Registered name of that autonomous system, e.g. "CLOUDFLARENET - Cloudflare, Inc., US". | WIKIMEDIA - Wikimedia Foundation Inc., US |
hostingCountry | string | Country code of the announcing network prefix. | US |
rdapServer | string | Base URL of the RDAP server that answered. | https://rdap.publicinterestregistry.org/rdap/ |
rdapSource | string | How the server was chosen: iana-bootstrap (IANA RDAP bootstrap file), registry-unlisted (official registry RDAP server not yet in the IANA file: .io .sh .ac .me .us .ch .li), rdap.org (fallback used only when the IANA file is unreachable). | iana-bootstrap |
sourceUrl | string | RDAP URL of the domain record. | https://rdap.publicinterestregistry.org/rdap/domain/wikipedia.org |
scrapedAt | string | Time of the lookup, ISO 8601 UTC. | 2026-10-01T08:00:00.000Z |
{
"input": "https://www.wikipedia.org/wiki/Domain",
"domain": "wikipedia.org",
"tld": "org",
"found": true,
"registered": true,
"reason": null,
"registrar": "MarkMonitor Inc.",
"registrarIanaId": 292,
"registrarAbuseEmail": "abusecomplaints@markmonitor.com",
"createdAt": "2001-01-13T00:12:14.754Z",
"updatedAt": "2026-08-12T08:47:19.410Z",
"expiresAt": "2027-01-13T00:12:14.000Z",
"domainAgeDays": 9391,
"daysToExpiry": 104,
"status": [
"clientDeleteProhibited",
"clientTransferProhibited",
"clientUpdateProhibited"
],
"transferLocked": true,
"deletionPending": false,
"nameservers": [
"ns0.wikimedia.org",
"ns1.wikimedia.org",
"ns2.wikimedia.org"
],
"dnssec": false,
"registrantOrganization": "Wikimedia Foundation, Inc.",
"registrantCountry": "US",
"registrantRedacted": false,
"registrarRdap": "ok",
"dnsStatus": "ok",
"aRecords": [
"103.102.166.224"
],
"aaaaRecords": [
"2001:df2:e500:ed1a::1"
],
"mxRecords": [
"mx-in1001.wikimedia.org",
"mx-in2001.wikimedia.org"
],
"mailProvider": "Google Workspace",
"mailGateway": "Proofpoint",
"dnsNameservers": [
"ns0.wikimedia.org",
"ns1.wikimedia.org",
"ns2.wikimedia.org"
],
"dnsProvider": "Cloudflare",
"spfRecord": "v=spf1 include:_spf.google.com ~all",
"spfPolicy": "~all",
"dmarcRecord": "v=DMARC1; p=reject; rua=mailto:dmarc-rua@wikimedia.org;",
"dmarcPolicy": "reject",
"dkimSelectors": [
"google"
],
"hostingIp": "103.102.166.224",
"hostingAsn": 14907,
"hostingAsnName": "WIKIMEDIA - Wikimedia Foundation Inc., US",
"hostingCountry": "US",
"rdapServer": "https://rdap.publicinterestregistry.org/rdap/",
"rdapSource": "iana-bootstrap",
"sourceUrl": "https://rdap.publicinterestregistry.org/rdap/domain/wikipedia.org",
"scrapedAt": "2026-10-01T08:00:00.000Z"
}
| Field | Name | Type | What it does |
|---|---|---|---|
domains | Domains | array | Domain names, one per line. URLs, www. hostnames, subdomains and e-mail addresses are accepted and reduced to the registered domain (https://blog.example.co.uk/x -> example.co.uk). Duplicates are merged. Entries that are not a domain are skipped and listed in the run status; if none is valid the run fails. With an empty list the Actor runs a small free example lookup (stripe.com, wikipedia.org, bbc.co.uk, lemonde.fr, google.io, google.de) and says so in the status message. |
includeDns | Include DNS, mail provider, SPF and DMARC | boolean | Query A, AAAA, MX, NS and TXT records, the DMARC record and common DKIM selectors for every registered domain, and detect the mail provider, mail security gateway and DNS provider. Turn off for registration data only. |
includeHosting | Include hosting ASN | boolean | Map the first IPv4 address of the domain to its network (ASN number, network name and country) through the public Team Cymru IP-to-ASN DNS service. Needs DNS to be included. |
registrantFromRegistrar | Registrant from registrar RDAP | boolean | For registries that publish no registrant (for example .com, .net, .org), make a second request to the registrar's own RDAP server to read the registrant organization and country. Registrar servers are rate-limited (GoDaddy allows about 6 requests per minute), so large lists run slower; domains skipped because of a registrar limit are marked registrarRdap = rateLimited. |
onlyAvailable | Only available domains | boolean | Return only domains with no registration at the registry (RDAP answers not found and the name is not delegated in DNS). Cannot be combined with the expiry, registration date or registrar filters. |
expiringWithinDays | Expiring within days | integer | Keep only registered domains whose registry expiry date is at most this many days away (daysToExpiry <= N), including domains already past expiry that the registry still holds. Domains whose registry publishes no expiry date (for example .ch) are dropped by this filter. 0 disables the filter. |
registeredAfter | Registered on or after | string | Keep only registered domains created on or after this date (YYYY-MM-DD, compared with createdAt in UTC). Domains without a creation date are dropped. |
registeredBefore | Registered before | string | Keep only registered domains created before this date (YYYY-MM-DD, the date itself excluded). Domains without a creation date are dropped. |
registrarContains | Registrar contains | array | Keep only registered domains whose registrar name contains one of these words (case-insensitive), for example GoDaddy or Namecheap. |
maxItems | Maximum results | integer | Stop after this many returned domains. Domains not looked up because of this limit are listed in the run status. |
proxyConfiguration | Proxy configuration | object | Optional proxy for the RDAP requests. Leave disabled: RDAP servers are public. DNS queries never go through the proxy. |
Run the Actor and get the results in one request. Replace YOUR_APIFY_TOKEN with the token from your Apify account settings.
curl -X POST "https://api.apify.com/v2/acts/datagrit~domain-whois-rdap-lookup/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"domains":["stripe.com","shopify.com","atlassian.com","nature.com","wikipedia.org","mozilla.org","bbc.co.uk","lemonde.fr","web.dev","google.io","google.us","zzqx-nonexist-8841.com"]}'import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('datagrit/domain-whois-rdap-lookup').call({
"domains": [
"stripe.com",
"shopify.com",
"atlassian.com",
"nature.com",
"wikipedia.org",
"mozilla.org",
"bbc.co.uk",
"lemonde.fr",
"web.dev",
"google.io",
"google.us",
"zzqx-nonexist-8841.com"
]
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);Install with npm i apify-client.
from apify_client import ApifyClient
import os
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("datagrit/domain-whois-rdap-lookup").call(run_input={
"domains": [
"stripe.com",
"shopify.com",
"atlassian.com",
"nature.com",
"wikipedia.org",
"mozilla.org",
"bbc.co.uk",
"lemonde.fr",
"web.dev",
"google.io",
"google.us",
"zzqx-nonexist-8841.com"
]
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(len(items), items[0] if items else None)Install with pip install apify-client.
Detect the technology stack of any list of domains: CMS, ecommerce, analytics, CDN, frameworks with versions, plus mail provider, SPF and DMARC.
Find EU public contracts approaching expiry from TED award notices: incumbent, buyer, value, end date and renewal options.
French company lead lists from Sirene screened by net result and revenue, with net margin, size, matching establishment and optional directors.
Ashby job postings with normalized annual salary ranges, equity flags and new-since-last-run detection.