DEV Community

Alex Spinov
Alex Spinov

Posted on

RDAP Is Replacing WHOIS — And It Returns Structured JSON For Free

WHOIS Is Broken

If you've ever tried to parse WHOIS data programmatically, you know the pain:

  • Every registrar returns a different format
  • The output is plain text with no standard structure
  • Rate limits are aggressive
  • Some registrars just... don't respond

Enter RDAP

RDAP (Registration Data Access Protocol) is the official replacement for WHOIS, standardized by IETF (RFC 7480-7484).

The key difference: it returns structured JSON.

curl https://rdap.org/domain/github.com
Enter fullscreen mode Exit fullscreen mode

You get:

{
  "objectClassName": "domain",
  "handle": "D1GITHUB-COM",
  "ldhName": "github.com",
  "status": ["client delete prohibited", "client transfer prohibited"],
  "events": [
    {"eventAction": "registration", "eventDate": "2007-10-09T18:20:50Z"},
    {"eventAction": "expiration", "eventDate": "2026-10-09T07:00:00Z"}
  ],
  "nameservers": [...]
}
Enter fullscreen mode Exit fullscreen mode

No auth. No API key. Structured JSON.

Real Example: Domain Intelligence Script

import requests
from datetime import datetime

def domain_intel(domain):
    """Get structured domain intelligence via RDAP."""
    resp = requests.get(f"https://rdap.org/domain/{domain}")
    if resp.status_code != 200:
        return {"error": f"Not found: {domain}"}

    data = resp.json()
    events = {e["eventAction"]: e["eventDate"][:10] 
              for e in data.get("events", [])}

    # Calculate domain age
    reg_date = events.get("registration", "unknown")
    if reg_date != "unknown":
        age_days = (datetime.now() - datetime.strptime(reg_date, "%Y-%m-%d")).days
        age_years = round(age_days / 365.25, 1)
    else:
        age_years = "unknown"

    return {
        "domain": domain,
        "status": data.get("status", []),
        "registered": reg_date,
        "expires": events.get("expiration", "unknown"),
        "age_years": age_years,
        "nameservers": [ns.get("ldhName", "") 
                        for ns in data.get("nameservers", [])]
    }

# Test with popular domains
for domain in ["github.com", "google.com", "dev.to"]:
    info = domain_intel(domain)
    print(f"\n{info['domain']}:")
    print(f"  Age: {info['age_years']} years")
    print(f"  Expires: {info['expires']}")
    print(f"  NS: {info['nameservers'][:2]}")
Enter fullscreen mode Exit fullscreen mode

Bulk Domain Analysis

import csv
import time

def bulk_analyze(domains):
    """Analyze multiple domains, output CSV."""
    results = []
    for domain in domains:
        info = domain_intel(domain)
        results.append(info)
        time.sleep(0.5)  # Be polite

    with open("domain_report.csv", "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=results[0].keys())
        writer.writeheader()
        writer.writerows(results)

    print(f"Analyzed {len(results)} domains → domain_report.csv")

# Example: check competitor domains
bulk_analyze(["competitor1.com", "competitor2.io", "competitor3.dev"])
Enter fullscreen mode Exit fullscreen mode

WHOIS vs RDAP

Feature WHOIS RDAP
Format Plain text, varies Structured JSON
Standard De facto IETF RFC 7480-7484
Auth None None
Rate limits Aggressive More generous
Parsing Custom regex per registrar json.loads()
GDPR compliant Partial Yes

Use Cases

  • Competitive intelligence: Track when competitor domains expire
  • Brand protection: Monitor similar domain registrations
  • Security: Verify domain age (new domains = higher risk)
  • Due diligence: Check company domain history before partnerships

Full toolkit: whois-lookup-tools
More free APIs: awesome-free-apis-2026


Still using raw WHOIS? What's your domain lookup workflow? 👇

Top comments (0)