
What Is RDAP, and How Is It Replacing WHOIS?
For decades, the answer to "who registered this domain?" came from WHOIS, a plain-text protocol that predates the web. It worked, but every server formatted its output differently, nothing was encrypted, and there was no way to show different data to different users. The Registration Data Access Protocol (RDAP) was designed to fix all of that, and for generic top-level domains it has now officially replaced WHOIS. This article explains what RDAP is, how it differs from WHOIS, how bootstrap discovery finds the right server, how to read an RDAP response, and how to query it with curl, Python, and Node.js. If you need a refresher on the older system first, start with what WHOIS is and how to look up domain ownership.
What Is RDAP?
RDAP is a protocol for looking up registration data for internet resources: domain names, IP address blocks, and autonomous system numbers. It was developed by the IETF and published as a set of standards, and it is built on familiar web technology:
- Queries are HTTPS GET requests to predictable URLs.
- Responses are JSON with a standardized structure.
- Errors use normal HTTP status codes such as 404 and 429.
- Servers are discovered through bootstrap files published by IANA.
In short, RDAP is WHOIS rebuilt as a RESTful web API. The same registries and registrars that ran WHOIS servers now run RDAP servers, and the data comes from the same registration databases.
The RDAP Standards
| RFC | Covers |
|---|---|
| RFC 7480 | How RDAP uses HTTP, including content types and status codes |
| RFC 7481 | Security services: HTTPS, authentication, and access control |
| RFC 9082 | The query format, meaning the URL paths for domains, IPs, and more |
| RFC 9083 | The JSON response format |
| RFC 9224 | Bootstrap: how clients find the authoritative RDAP server |
| RFC 8056 | Mapping of EPP status codes to RDAP status values |
RFCs 9082, 9083, and 9224 replaced the original 7482, 7483, and 7484 with clarifications, so you will see both sets of numbers in older documentation.
Why WHOIS Needed Replacing
WHOIS (RFC 3912) is a text query sent to port 43, answered by a block of free-form text. That simplicity caused real problems:
| Problem with WHOIS | How RDAP addresses it |
|---|---|
| No standard output format | Standardized JSON with defined field names |
| No encryption | Runs over HTTPS |
| No way to find the right server | IANA bootstrap files map TLDs and IP ranges to RDAP servers |
| Poor support for non-ASCII text | UTF-8 JSON and support for internationalized domain names |
| One view of data for everyone | Supports authentication and differentiated access |
| Errors buried in text | HTTP status codes and structured error responses |
| Hard to link related records | links objects point to related records, such as the registrar's copy |
The privacy point became urgent after GDPR. Regulators expected personal data to be hidden from the public but available to parties with a legitimate need. WHOIS cannot tell one requester from another; RDAP can, at least in principle, return more fields to authenticated, authorized users.
The Transition Timeline
- 2015: The core RDAP RFCs are published.
- 26 August 2019: ICANN requires gTLD registries and registrars to provide RDAP services.
- 28 January 2025: The WHOIS "sunset" takes effect. gTLD registries and registrars are no longer contractually required to provide port 43 WHOIS, and RDAP becomes the definitive source for gTLD registration data.
Some gTLD operators still run WHOIS servers for compatibility, but you should not rely on them. Country-code TLDs set their own rules: many ccTLD registries offer RDAP, while others still use only WHOIS or a web form. The IANA bootstrap file, covered next, shows which TLDs have registered RDAP servers. The Regional Internet Registries (ARIN, RIPE NCC, APNIC, LACNIC, and AFRINIC) all run RDAP for IP and ASN data.
How RDAP Bootstrap Works
With WHOIS, finding the right server for a TLD meant asking IANA or relying on a hardcoded list in your client. RDAP formalizes this through bootstrap (RFC 9224). IANA publishes JSON files listing which RDAP base URLs serve which resources:
https://data.iana.org/rdap/dns.jsonfor domain TLDshttps://data.iana.org/rdap/ipv4.jsonandipv6.jsonfor IP rangeshttps://data.iana.org/rdap/asn.jsonfor AS numbers
The domain file looks like this, abridged:
{
"version": "1.0",
"publication": "2026-10-20T19:00:01Z",
"services": [
[["com", "net"], ["https://rdap.verisign.com/com/v1/"]],
[["org"], ["https://rdap.publicinterestregistry.org/rdap/"]]
]
}
Each entry pairs a list of TLDs with one or more base URLs. A client takes the TLD of the domain being queried, finds the matching entry, and appends domain/ plus the name to the base URL. For example.com, that gives https://rdap.verisign.com/com/v1/domain/example.com.
If you do not want to implement bootstrap yourself, the community-run redirector at rdap.org does it for you: https://rdap.org/domain/example.com returns an HTTP redirect to the correct registry server.
Registry and Registrar Records
For thin registries such as .com, the registry RDAP response contains the domain's registrar, dates, statuses, and name servers, but not the full contact data. It includes a links entry with "rel": "related" that points to the registrar's RDAP server, where the full (and usually redacted) contact record lives. ICANN Lookup and good RDAP clients follow that link automatically. To understand why there are two records, see registry vs. registrar.
Querying RDAP With curl
A simple domain query:
curl -sL https://rdap.org/domain/example.com
The -L flag follows the redirect from rdap.org to the registry. It is good practice to send the RDAP media type in the Accept header:
curl -sL -H "Accept: application/rdap+json" https://rdap.verisign.com/com/v1/domain/example.com
With jq, you can pull out exactly the fields you need:
# Status codes
curl -sL https://rdap.org/domain/example.com | jq -r '.status[]'
# Registration and expiration dates
curl -sL https://rdap.org/domain/example.com \
| jq -r '.events[] | "\(.eventAction): \(.eventDate)"'
# Name servers
curl -sL https://rdap.org/domain/example.com | jq -r '.nameservers[].ldhName'
# The registrar's own RDAP record, if the registry links to it
curl -sL https://rdap.org/domain/example.com \
| jq -r '.links[]? | select(.rel == "related") | .href'
RDAP also covers IP addresses and AS numbers. For example, against ARIN:
curl -s https://rdap.arin.net/registry/ip/8.8.8.8 | jq '{name, handle, startAddress, endAddress}'
curl -s https://rdap.arin.net/registry/autnum/15169 | jq '{name, handle}'
If an address belongs to another region, ARIN redirects you to the right RIR, so add -L when in doubt.
Reading an RDAP Domain Response
Here is a trimmed RDAP response for a domain:
{
"objectClassName": "domain",
"ldhName": "EXAMPLEBRAND.COM",
"handle": "1234567890_DOMAIN_COM-VRSN",
"status": ["client transfer prohibited"],
"events": [
{ "eventAction": "registration", "eventDate": "2015-06-02T17:40:11Z" },
{ "eventAction": "expiration", "eventDate": "2027-06-02T17:40:11Z" },
{ "eventAction": "last changed", "eventDate": "2026-03-14T09:12:44Z" },
{
"eventAction": "last update of RDAP database",
"eventDate": "2026-10-26T08:00:00Z"
}
],
"entities": [
{
"objectClassName": "entity",
"handle": "9999",
"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.EXAMPLEDNS.NET" },
{ "objectClassName": "nameserver", "ldhName": "NS2.EXAMPLEDNS.NET" }
],
"secureDNS": { "delegationSigned": false },
"links": [
{
"rel": "related",
"type": "application/rdap+json",
"href": "https://rdap.example-registrar.com/domain/EXAMPLEBRAND.COM"
}
]
}
The key members:
ldhName: the domain in "letters, digits, hyphen" form. Internationalized domains also includeunicodeName.status: EPP statuses in RDAP form.clientTransferProhibitedbecomesclient transfer prohibited, andokbecomesactive, per RFC 8056. See what registrar lock is for what each means.events: dated lifecycle events.registrationandexpirationare the ones you will use most.entities: people and organizations attached to the domain, each withrolessuch asregistrar,registrant,administrative,technical,billing, orabuse. Contact details are invcardArray, which uses the jCard format (RFC 7095). The roles are explained in registrant vs. admin vs. technical contact.nameservers: the delegated name servers.secureDNS: DNSSEC delegation information.links: related resources, including the registrar's record.noticesandremarks: terms of service, redaction explanations, and links to ICANN's status code documentation.
Redaction in RDAP
Personal data that would be public in old WHOIS records is usually redacted in RDAP too. Servers either omit the fields, fill them with placeholder text, or list them in a redacted member that names which fields were removed and why. A registrant entity might show only an organization, state or province, and country. This is the same privacy behavior covered in what WHOIS privacy protection is, expressed in JSON.
Errors and Rate Limits
RDAP servers use HTTP status codes:
| Code | Meaning in RDAP |
|---|---|
| 200 | Object found |
| 302, 301 | Redirect, usually from a bootstrap redirector or another RIR |
| 400 | Malformed query |
| 404 | Object not found, which for a domain usually means not registered |
| 429 | Too many requests; slow down |
A 404 from the correct registry is a useful (though not conclusive) signal that a domain is unregistered. Reserved and premium names can still return 404 while being unavailable, so confirm with a registrar before celebrating. For the full method, see how to check if a domain name is available.
Querying RDAP in Code
Python With Bootstrap
This standard-library script downloads the IANA bootstrap file once, finds the right server for each domain, and prints key data:
import json
import urllib.error
import urllib.request
BOOTSTRAP_URL = "https://data.iana.org/rdap/dns.json"
HEADERS = {"Accept": "application/rdap+json"}
def fetch_json(url: str) -> dict:
req = urllib.request.Request(url, headers=HEADERS)
with urllib.request.urlopen(req, timeout=15) as resp:
return json.load(resp)
def load_bootstrap() -> dict:
data = fetch_json(BOOTSTRAP_URL)
mapping = {}
for tlds, urls in data["services"]:
for tld in tlds:
mapping[tld.lower()] = urls[0]
return mapping
def rdap_domain(domain: str, bootstrap: dict) -> dict | None:
tld = domain.rsplit(".", 1)[-1].lower()
base = bootstrap.get(tld)
if base is None:
raise ValueError(f"No RDAP server registered for .{tld}")
if not base.endswith("/"):
base += "/"
try:
return fetch_json(f"{base}domain/{domain}")
except urllib.error.HTTPError as exc:
if exc.code == 404:
return None
raise
def summarize(domain: str, data: dict | None) -> None:
if data is None:
print(f"{domain}: not found at registry (possibly available)")
return
events = {e["eventAction"]: e["eventDate"] for e in data.get("events", [])}
registrar = next(
(
ent.get("vcardArray", [None, []])[1]
for ent in data.get("entities", [])
if "registrar" in ent.get("roles", [])
),
[],
)
registrar_name = next((f[3] for f in registrar if f[0] == "fn"), "unknown")
print(f"{domain}")
print(f" registrar: {registrar_name}")
print(f" registered: {events.get('registration', 'n/a')}")
print(f" expires: {events.get('expiration', 'n/a')}")
print(f" status: {', '.join(data.get('status', []))}")
if __name__ == "__main__":
bootstrap = load_bootstrap()
for name in ["example.com", "example.org", "this-name-is-probably-free-123.com"]:
summarize(name, rdap_domain(name, bootstrap))
The dict | None type hints require Python 3.10 or newer. In production, cache the bootstrap file for a day rather than downloading it on every run, and add a delay between queries to respect rate limits.
Node.js
Node 18 and later include fetch, which follows redirects by default:
async function rdapDomain(domain) {
const res = await fetch(`https://rdap.org/domain/${domain}`, {
headers: { Accept: "application/rdap+json" },
});
if (res.status === 404) return null;
if (!res.ok) throw new Error(`RDAP lookup failed: HTTP ${res.status}`);
return res.json();
}
const domain = process.argv[2] || "example.com";
const data = await rdapDomain(domain);
if (!data) {
console.log(`${domain}: not found`);
} else {
const expiry = data.events?.find((e) => e.eventAction === "expiration");
console.log({
domain: data.ldhName,
status: data.status,
expires: expiry?.eventDate ?? "n/a",
nameservers: (data.nameservers || []).map((ns) => ns.ldhName),
});
}
Save it as rdap.mjs (top-level await needs an ES module) and run node rdap.mjs example.com.
Practical Uses for RDAP
- Expiry monitoring: check
expirationevents across your portfolio and alert well ahead of time. This complements setting up domain auto-renewal. - Lock monitoring: alert if a domain's statuses no longer include a transfer prohibition.
- Name server change detection: compare
nameserverswith a known-good list to catch hijacking early. - Abuse reporting: find the registrar's
abuseentity for phishing or malware reports. - Availability research: a 404 from the authoritative server is a quick first filter.
- IP and ASN lookups: identify which network owns an address in logs.
Limitations of RDAP
RDAP is a clear improvement, but it is not perfect:
- Data is still redacted. RDAP supports tiered access, but for most users the public view hides the same personal data that WHOIS did.
- Coverage is uneven outside gTLDs. Some ccTLDs have no RDAP server in the bootstrap file.
- Implementations differ in detail. Field usage, redaction markers, and extensions vary between operators, so robust code checks for missing fields.
- Rate limits apply. Bulk queries can get you temporarily blocked.
RDAP FAQ
No. Both provide registration data, but WHOIS returns unstructured text over port 43, while RDAP returns standardized JSON over HTTPS with defined fields, error codes, and bootstrap discovery. For gTLDs, RDAP is now the authoritative source.
For gTLDs, ICANN stopped requiring registries and registrars to run port 43 WHOIS as of 28 January 2025. Some still run it, but it is no longer guaranteed. Many ccTLDs still operate WHOIS under their own policies.
No. Public RDAP queries require no authentication. Servers may rate limit heavy use, and some offer extra data to authenticated, authorized users such as law enforcement.
Usually not for individuals. Personal data is redacted under privacy law and registrar policy. You may see the organization, state or province, and country, plus a way to contact the registrant through the registrar.
It is a community-run redirector that uses the IANA bootstrap files to send your query to the correct RDAP server. It is convenient for quick lookups, but production systems can read the bootstrap files directly.
The registry has no record of that name, which usually means it is not registered. Reserved, blocked, or premium names may also return 404, so confirm availability with a registrar.
Yes. The Regional Internet Registries run RDAP servers for IP address blocks and autonomous system numbers, and the IANA bootstrap files map address ranges to the right registry.
Conclusion
RDAP takes everything WHOIS did and puts it on a modern footing: HTTPS instead of plain TCP, standardized JSON instead of free-form text, HTTP status codes instead of error messages buried in prose, and IANA bootstrap files instead of guesswork about which server to ask. Since January 2025 it is the definitive source of registration data for gTLDs, and it already covers IP addresses and AS numbers across all five Regional Internet Registries.
For everyday use, ICANN Lookup or curl against rdap.org will answer most questions. For anything automated, such as expiry alerts, lock monitoring, or portfolio reports, query RDAP directly with a short script and parse the JSON rather than scraping WHOIS text. Expect personal data to stay redacted, and handle missing fields gracefully, because implementations vary.
Here are some useful references for going deeper on RDAP:
- ICANN: Registration Data Access Protocol (RDAP) — ICANN's overview of RDAP and the WHOIS transition.
- RFC 9083: JSON Responses for the Registration Data Access Protocol — defines the response format, including entities, events, and links.
- RFC 9082: Registration Data Access Protocol (RDAP) Query Format — defines the URL paths for each query type.
- RFC 9224: Finding the Authoritative Registration Data Access Protocol (RDAP) Service — the bootstrap specification.
- IANA: Bootstrap Service Registry for Domain Name Space — the live JSON file mapping TLDs to RDAP servers.


