Domain Checker
Check domain availability in bulk using RDAP (Registration Data Access Protocol) as the primary signal, with WHOIS and DNS fallbacks. Python stdlib only.
When to Use
- User asks "is
<domain>available / taken / registered?" - User wants to check many domains at once (a list, a file, names piped in)
- User wants to test a brand name across many TLDs (
acme.com,acme.net,acme.io, …) - User wants machine-readable output (CSV/JSON) for further processing
- User wants only available (or only taken) results filtered
Do NOT use for: WHOIS contact lookup (this skill only checks existence), DNS record inspection (use dig), trademark/legal availability (this only checks registration status).
How It Works
- RDAP first — fetches the IANA RDAP bootstrap (
data.iana.org/rdap/dns.json, cached 24h in~/.cache/domain-checker/) to find the authoritative RDAP server for each TLD.HTTP 404= available,HTTP 200= taken. - WHOIS fallback — if RDAP is unavailable for a TLD (notably
.io, some ccTLDs) or returns ambiguous, shells out to the localwhoisCLI and matches well-known "not found"/"registered" patterns. - DNS — optional, weak signal. Resolves A/AAAA records. Confirms "taken" only — registered-but-unhosted domains will show no DNS, so DNS alone cannot prove "available".
After the primary check, three enrichment passes refine accuracy:
- Aftermarket detection — parses the RDAP response we already fetched. Flags
aftermarketwhen the registrant/entity name matches a known reseller (HugeDomains, Sedo, Afternic, Dan.com, NameJet, DropCatch, …) OR when the nameservers match parking patterns (sedoparking.com,parkingcrew.net,namefind.com,afternic.com,bodis.com, …). Free — no extra requests. - RDAP status parsing — surfaces
pendingDelete/redemptionPeriod/clientHold/serverHoldas a separateexpiringstatus (these domains may drop and become available within ~30 days). - Premium-likely hint — for
availableresults, appends a warning when the name is short (≤5chars on.ai/.io/.app/.dev/.co/.tv/.me/.cc/.tech/.xyzor≤3chars on.com/.net/.org). This is a heuristic, not a hard claim — the registrar checkout has the real price. - Optional HTTP sale-page probe (
--probe-sale) — fetches the homepage and looks for "for sale" / Sedo / Dan.com / HugeDomains / Afternic markers. Reclassifiestaken→aftermarketon a hit. Off by default; adds ~1s per checked domain.
Concurrency via ThreadPoolExecutor (default 10 workers). Per-request timeout default 8s.
Prerequisites
- Python 3.8+ (stdlib only)
- Outbound HTTPS to RDAP servers
- Optional:
whoisCLI (brew install whois/apt install whois) for fallback on TLDs without RDAP
Quick Routing
| Task | Command | |------|---------| | Check single domain | check_domains.py acme.com | | Check many domains | check_domains.py acme.com acme.net acme.io | | Bare name across TLDs | check_domains.py acme --tlds com,net,io,ai,dev | | From a file | check_domains.py --file domains.txt | | From stdin | cat list.txt \| check_domains.py --stdin | | Only available | check_domains.py --file list.txt --only-available | | JSON output | check_domains.py acme.com --format json | | CSV output | check_domains.py acme.com --format csv | | Force WHOIS only | check_domains.py acme.io --method whois | | Fastest (DNS only) | check_domains.py acme.com --method dns |
Usage
python3 .claude/skills/domain-checker/scripts/check_domains.py [DOMAINS...] [OPTIONS]
Examples
# Single domain
python3 scripts/check_domains.py google.com
# Many domains
python3 scripts/check_domains.py acme.com acme.net brandidea.io
# Brand-name search across TLDs
python3 scripts/check_domains.py mybrand --tlds com,net,io,ai,dev,app
# From a file (one domain per line, # comments allowed)
python3 scripts/check_domains.py --file domains.txt
# From stdin
printf 'foo.com\nbar.io\n' | python3 scripts/check_domains.py --stdin
# Only available, as CSV (great for piping into a sheet)
python3 scripts/check_domains.py --file candidates.txt --only-available --format csv > available.csv
# JSON for programmatic use
python3 scripts/check_domains.py acme --tlds com,net,io --format json
# Higher parallelism for big lists
python3 scripts/check_domains.py --file 500-domains.txt -c 25
# Exit code reflects unknown/invalid results (for CI)
python3 scripts/check_domains.py --file list.txt --exit-code
Output
Default table format:
domain status method evidence ms
- ------------- ------------ ------ ---------------------------------------------------------- ----
✓ acme.dev available rdap RDAP 404 from https://pubapi.registry.google/rdap 437
✓ bzqj.dev available rdap RDAP 404 …; likely premium tier (.dev <=5 chars) 383
✗ google.com taken rdap RDAP 200 from https://rdap.verisign.com/com/v1 333
$ foothill.com aftermarket rdap RDAP 200 …; parking NS: ns1.afternic.com 352
~ someone.com expiring rdap RDAP 200 …; status: pendingdelete 340
? bizarre.tld unknown rdap no RDAP server for .tld 12
! bad..domain invalid invalid domain syntax 0
| Symbol | Status | Meaning | |--------|--------|---------| | ✓ | available | No registration record found (RDAP 404 or WHOIS no-match) | | ✗ | taken | Domain is registered (legit ownership) | | $ | aftermarket | Registered but held by a domain investor / parking service — usually for resale at premium prices | | ~ | expiring | Registered but in pendingDelete / redemptionPeriod / clientHold — may drop and become available | | ? | unknown | Neither method could decide (rate-limited, no RDAP server, etc.) — retry, or use a registrar to confirm | | ! | invalid | Domain syntax invalid | | · | reserved | TLD-reserved (rare, e.g. some registry-internal names) |
For available results, the evidence column may include likely premium tier (...) — a heuristic warning that the registry probably charges a premium for this short name on this TLD.
Flags
| Flag | Default | Description | |------|---------|-------------| | positional DOMAINS | — | Zero or more domains or bare names | | -f, --file PATH | — | Read domains from file (one per line, # comments OK) | | --stdin | off | Read domains from stdin | | --tlds com,net,... | — | TLDs to append to bare names (only used for inputs without a .) | | -m, --method | auto | auto (rdap→whois), rdap, whois, dns, or comma list | | -c, --concurrency N | 10 | Parallel workers | | -t, --timeout S | 8.0 | Per-request timeout, seconds | | --format | table | table, json, or csv | | --only-available | off | Filter output to available only | | --only-taken | off | Filter output to taken / aftermarket / expiring | | --no-color | off | Disable ANSI colors in table output | | --no-aftermarket-detect | off | Skip RDAP entity / nameserver analysis (faster, less accurate) | | --no-premium-hint | off | Don't warn on short available names | | --probe-sale | off | HTTP-probe taken domains for "for sale" landing pages (~1s/domain) | | --exit-code | off | Exit non-zero if any unknown/invalid result (useful in CI) |
--only-available and --only-taken are mutually exclusive (last one wins).
Method Notes
| Method | Pros | Cons | |--------|------|------| | rdap | Standardized JSON; works for nearly all gTLDs; fast; no parsing fragility | Some ccTLDs (.io, .co.uk, …) don't expose RDAP | | whois | Covers TLDs without RDAP | Output format varies per registry; rate-limited; requires CLI installed | | dns | Very fast | C