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 |