
What is RDAP and how is it replacing WHOIS?
RDAP (Registration Data Access Protocol) is the modern replacement for WHOIS. It lets you look up registration data for domain names, IP addresses and autonomous system numbers, but instead of returning free-form text over port 43, it returns structured JSON over HTTPS with standard field names, proper support for international characters, and the ability to show different data to different users. ICANN required gTLD registries and registrars to support RDAP from 2019, and on 28 January 2025 it ended the requirement to run WHOIS, making RDAP the authoritative lookup service for gTLDs. You can query it with a simple request such as curl https://rdap.org/domain/example.com.
If you've ever tried to parse WHOIS output in a script, you'll appreciate the difference straight away. This guide explains why WHOIS was replaced, how RDAP works, how servers are discovered through IANA's bootstrap files, how to read an RDAP response, and how to query it from the command line, Python and JavaScript.
Why WHOIS Needed Replacing
WHOIS served the internet for decades, but it was designed for a much smaller network and has fundamental limitations:
- No standard format. Every registry and registrar formats output differently, so parsing it reliably is painful.
- No internationalisation. The protocol doesn't define a character encoding, so non-ASCII names and addresses are handled inconsistently.
- No security. Queries and responses travel in plain text, with no way to verify the server.
- No access control. Everyone gets the same answer, which makes it impossible to show full data to authorised users while hiding it from the public.
- No discovery. There's no standard way to know which server to ask for a given domain.
Data protection laws such as GDPR made the last two problems urgent, because registries needed to redact personal data for the public while still meeting legitimate requests.
How RDAP Works
RDAP is a RESTful protocol defined by the IETF in a series of RFCs, first published in 2015 and since updated. The key ideas are simple.
HTTPS and Predictable URLs
Every lookup is an HTTPS GET request to a predictable path:
| Object | Path |
|---|---|
| Domain | /domain/example.com |
| Name server | /nameserver/ns1.example.com |
| Contact or registrar entity | /entity/<handle> |
| IP network | /ip/192.0.2.0 |
| Autonomous system | /autnum/64496 |
| Server help | /help |
Responses use the media type application/rdap+json, and standard HTTP status codes tell you what happened.
Standard Status Codes
| Status | Meaning |
|---|---|
200 | Object found, data returned |
404 | Object not found, for a domain usually meaning it isn't registered |
400 | Bad request, such as an invalid domain name |
429 | Rate limited, slow down |
301, 302, 303 | Redirect to another RDAP server |
That 404 is useful for availability checks, though a missing record doesn't guarantee you can register a name, because registries may reserve or block some names.
Bootstrapping: Finding the Right Server
RDAP solves WHOIS's discovery problem with bootstrap files published by IANA. For domains, the file at https://data.iana.org/rdap/dns.json maps each TLD to its registry's RDAP base URL. A client reads the file, finds the base URL for the TLD and appends the query path.
You can do this by hand with jq:
curl -s https://data.iana.org/rdap/dns.json \
| jq -r '.services[] | select(.[0] | index("com")) | .[1][]'
https://rdap.verisign.com/com/v1/
Then query the registry directly:
curl -s https://rdap.verisign.com/com/v1/domain/example.com | jq .
Similar bootstrap files exist for IPv4 (ipv4.json), IPv6 (ipv6.json) and AS numbers (asn.json) under the same IANA path.
The public service at rdap.org does this lookup for you and redirects to the right server, which is handy for quick checks. Use -L with curl so it follows the redirect:
curl -s -L https://rdap.org/domain/example.com | jq .
Not every ccTLD appears in the bootstrap file, because ccTLD registries aren't bound by ICANN's requirements. If a TLD is missing, it either doesn't offer RDAP or hasn't registered its service with IANA, and you may need to fall back to WHOIS or the registry's website.
Differentiated Access
Because RDAP runs over HTTPS, servers can authenticate users and return different levels of detail to each. Anonymous users see redacted public data, while authorised parties, such as law enforcement under an agreed process, could see more. In practice, public RDAP responses today look similar to public WHOIS: personal contact data is redacted. See what is domain privacy protection for what that means for registrants.
Reading an RDAP Domain Response
Here's a trimmed response for a .com domain from the registry:
{
"objectClassName": "domain",
"handle": "2336799_DOMAIN_COM-VRSN",
"ldhName": "EXAMPLE.COM",
"status": [
"client delete prohibited",
"client transfer prohibited",
"client update prohibited"
],
"events": [
{ "eventAction": "registration", "eventDate": "1995-08-14T04:00:00Z" },
{ "eventAction": "expiration", "eventDate": "2027-08-13T04:00:00Z" },
{ "eventAction": "last changed", "eventDate": "2026-08-14T07:01:34Z" },
{
"eventAction": "last update of RDAP database",
"eventDate": "2026-10-26T08:15:02Z"
}
],
"entities": [
{
"objectClassName": "entity",
"roles": ["registrar"],
"publicIds": [{ "type": "IANA Registrar ID", "identifier": "9999" }],
"vcardArray": [
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "Example Registrar, LLC"]
]
]
}
],
"nameservers": [
{ "objectClassName": "nameserver", "ldhName": "NS1.EXAMPLE-DNS.NET" },
{ "objectClassName": "nameserver", "ldhName": "NS2.EXAMPLE-DNS.NET" }
],
"secureDNS": { "delegationSigned": true },
"links": [
{
"rel": "related",
"href": "https://rdap.example-registrar.com/domain/EXAMPLE.COM",
"type": "application/rdap+json"
}
]
}
The important parts:
- ldhName: The domain in ASCII ("letters, digits, hyphen") form. Internationalized domains also have a
unicodeName. See what is an internationalized domain name. - status: The EPP status codes, written in lowercase words.
client transfer prohibitedis RDAP's form ofclientTransferProhibited, the registrar lock. - events: Dated events, including
registration,expirationandlast changed. - entities: Related parties, each with
rolessuch asregistrar,registrant,technicalorabuse, and contact data in jCard format (vcardArray), a JSON version of vCard. - nameservers: The domain's delegated name servers.
- secureDNS: Whether the domain is signed with DNSSEC.
- links: Related URLs. For thin registries like
.com, arelatedlink points to the registrar's RDAP server, which holds the fuller record. - notices and remarks: Terms of use and explanatory text, omitted above for brevity.
Querying RDAP From the Command Line
Common jq Recipes
Get the expiry date:
curl -s -L https://rdap.org/domain/example.com \
| jq -r '.events[] | select(.eventAction == "expiration") | .eventDate'
List status codes:
curl -s -L https://rdap.org/domain/example.com | jq -r '.status[]'
Show the registrar's name:
curl -s -L https://rdap.org/domain/example.com \
| jq -r '.entities[] | select(.roles | index("registrar")) | .vcardArray[1][] | select(.[0] == "fn") | .[3]'
List name servers:
curl -s -L https://rdap.org/domain/example.com | jq -r '.nameservers[].ldhName'
Compare the name servers in the registration with what DNS actually returns, a quick sanity check when you change nameservers:
dig +short NS example.com
Following the Registrar Link
For .com and .net, the registrar holds contact and abuse details the registry doesn't. Follow the related link:
reg_url=$(curl -s -L https://rdap.org/domain/example.com \
| jq -r '.links[] | select(.rel == "related") | .href' | head -n 1)
curl -s "$reg_url" | jq '.entities[] | {roles, handle}'
IP Addresses
RDAP also covers IP addresses, served by the Regional Internet Registries such as ARIN, RIPE NCC and APNIC:
curl -s -L https://rdap.org/ip/8.8.8.8 | jq -r '.name, .startAddress, .endAddress'
Dedicated RDAP Clients
If you prefer a WHOIS-like command, open-source clients exist, such as the rdap tool from the OpenRDAP project, which handles bootstrapping for you:
rdap example.com
rdap --json example.com
On Windows, PowerShell can query RDAP without extra tools:
$r = Invoke-RestMethod "https://rdap.org/domain/example.com"
($r.events | Where-Object eventAction -eq "expiration").eventDate
Using RDAP in Your Own Code
Python
This script implements bootstrapping itself instead of relying on rdap.org, caches the bootstrap file in memory, and prints the key fields for each domain:
import json
import sys
import urllib.error
import urllib.request
BOOTSTRAP_URL = "https://data.iana.org/rdap/dns.json"
def fetch_json(url: str) -> dict:
req = urllib.request.Request(url, headers={"Accept": "application/rdap+json", "User-Agent": "domain-check/1.0"})
with urllib.request.urlopen(req, timeout=15) as resp:
return json.load(resp)
def build_bootstrap() -> dict[str, str]:
data = fetch_json(BOOTSTRAP_URL)
table = {}
for tlds, urls in data["services"]:
https_urls = [u for u in urls if u.startswith("https://")] or urls
for tld in tlds:
table[tld.lower()] = https_urls[0]
return table
def rdap_domain(domain: str, bootstrap: dict[str, str]) -> dict | None:
tld = domain.rstrip(".").rsplit(".", 1)[-1].lower()
base = bootstrap.get(tld)
if base is None:
raise ValueError(f"No RDAP service registered for .{tld}")
if not base.endswith("/"):
base += "/"
try:
return fetch_json(f"{base}domain/{domain}")
except urllib.error.HTTPError as err:
if err.code == 404:
return None
raise
def summarise(domain: str, data: dict | None) -> None:
if data is None:
print(f"{domain}: not found (possibly available)")
return
events = {e["eventAction"]: e["eventDate"] for e in data.get("events", [])}
registrar = next(
(
prop[3]
for ent in data.get("entities", [])
if "registrar" in ent.get("roles", [])
for prop in ent.get("vcardArray", [None, []])[1]
if prop[0] == "fn"
),
"unknown",
)
print(f"{domain}")
print(f" registrar: {registrar}")
print(f" registered: {events.get('registration', '-')}")
print(f" expires: {events.get('expiration', '-')}")
print(f" status: {', '.join(data.get('status', []))}")
if __name__ == "__main__":
table = build_bootstrap()
for name in sys.argv[1:]:
summarise(name, rdap_domain(name, table))
python3 rdap_lookup.py example.com example.org
example.com
registrar: Example Registrar, LLC
registered: 1995-08-14T04:00:00Z
expires: 2027-08-13T04:00:00Z
status: client delete prohibited, client transfer prohibited, client update prohibited
JavaScript (Node.js 18+)
Node's built-in fetch makes RDAP queries straightforward. Save this as rdap.mjs:
const BOOTSTRAP_URL = "https://data.iana.org/rdap/dns.json";
async function getBootstrap() {
const res = await fetch(BOOTSTRAP_URL);
const data = await res.json();
const table = new Map();
for (const [tlds, urls] of data.services) {
const url = urls.find((u) => u.startsWith("https://")) ?? urls[0];
for (const tld of tlds) table.set(tld.toLowerCase(), url);
}
return table;
}
async function lookup(domain, table) {
const tld = domain.split(".").pop().toLowerCase();
let base = table.get(tld);
if (!base) throw new Error(`No RDAP service for .${tld}`);
if (!base.endsWith("/")) base += "/";
const res = await fetch(`${base}domain/${domain}`, {
headers: {
Accept: "application/rdap+json",
"User-Agent": "domain-check/1.0",
},
});
if (res.status === 404) return { domain, registered: false };
if (!res.ok) throw new Error(`HTTP ${res.status} for ${domain}`);
const data = await res.json();
const expiry = data.events?.find(
(e) => e.eventAction === "expiration",
)?.eventDate;
return { domain, registered: true, expiry, status: data.status ?? [] };
}
const table = await getBootstrap();
for (const domain of process.argv.slice(2)) {
console.log(await lookup(domain, table));
}
node rdap.mjs example.com example.net
Being a Good RDAP Citizen
- Cache the bootstrap file. It changes rarely, so download it once a day rather than for every query.
- Respect rate limits. Registries throttle heavy use and return
429. Add a delay between requests and back off when limited. - Don't scrape. RDAP terms of use generally prohibit bulk harvesting and using the data for marketing.
- Handle missing fields. Not every server returns every field, so code defensively, as the scripts above do.
RDAP vs WHOIS at a Glance
| WHOIS | RDAP | |
|---|---|---|
| Transport | Plain TCP, port 43 | HTTPS |
| Format | Free-form text, varies by server | Standardised JSON |
| International characters | Not defined | Full Unicode support |
| Server discovery | None, you must know the server | IANA bootstrap files |
| Access control | None | Supports authenticated, tiered access |
| Errors | Ad hoc text | HTTP status codes |
| Status for gTLDs | Requirement ended 28 January 2025 | Required |
| Status for ccTLDs | Still widely used | Adoption varies by registry |
FAQ: RDAP
For gTLDs, RDAP is now the required lookup service, and ICANN ended the WHOIS requirement on 28 January 2025. Many registries still run WHOIS voluntarily, and many ccTLDs still rely on it, so both exist side by side for now.
Not for the public. RDAP returns largely the same public data, with personal details redacted. Its advantages are structure, consistency, security and the ability to give authorised users different access.
Yes. Registry and registrar RDAP services are free to query, subject to terms of use and rate limits. Services such as rdap.org and ICANN Lookup are also free.
Download IANA's bootstrap file at data.iana.org/rdap/dns.json, which maps each TLD to its RDAP base URL. Alternatively, use rdap.org, which redirects your query to the right server.
A 404 means the server has no record of that object. For a domain, that usually means it isn't registered, although some names are reserved or blocked by the registry and still can't be registered.
Yes, as a first check. A 404 suggests the name is unregistered and a 200 means it's registered. Confirm with a registrar before buying, because reserved and premium names may behave differently.
Conclusion
RDAP is the modern successor to WHOIS. It answers the same questions, who the registrar is, when a domain expires, which status codes and name servers it has, but does so over HTTPS with standard JSON, proper internationalisation, built-in server discovery and support for differentiated access. Since 28 January 2025 it has been the authoritative lookup service for gTLDs.
For everyday use, nothing much changes: ICANN Lookup and most WHOIS websites already use RDAP behind the scenes. For anyone writing scripts or monitoring domains, it's a big improvement. A single curl and jq command replaces fragile text parsing, and a few lines of Python or JavaScript give you reliable expiry, status and registrar data for every domain you manage.


