Domain Availability Auditing at Scale: Building a Multi-Prefix Registry Checker for the Queen Of Franchise Model
Overview
Ticket t-f860fe03 required determining domain availability across a portfolio of `queenof[city].com` domains—a franchise concept where local tour operators would operate signature vessels branded as "Queen of [City]." The challenge: efficiently querying domain registry data for ~130+ port cities worldwide without triggering rate-limiting from authoritative WHOIS servers.
This post documents the technical approach, infrastructure decisions, and why we pivoted from traditional WHOIS to RDAP (Registration Data Access Protocol) for reliable, high-volume registry queries.
The Problem: WHOIS Rate-Limiting at Scale
Our initial approach used Python's whois library against Verisign's authoritative registry. The implementation in /Users/cb/icloud-jada-ops/ticket-runner/check_queenof_domains.py worked for small sample sets but failed catastrophically at scale:
- Result: 130+ domains returned "unknown" status (timeout/rate-limit)
- Root cause: Verisign throttles WHOIS queries by client IP after ~20-30 consecutive lookups
- Impact: Even control domains like
queenofsandiego.com(known taken) returned unreliable status
This is a well-documented limitation in large-scale domain research: WHOIS is designed for interactive, ad-hoc queries, not batch operations. We needed a different approach.
Technical Solution: RDAP HTTP/JSON Registry Queries
We migrated to RDAP (RFC 7480), Verisign's HTTP-based registry endpoint. RDAP provides:
- HTTP semantics:
404 = available,200 = registered - JSON responses: Structured data vs. unformatted text
- Higher rate limits: Designed for automation; significantly less throttling than WHOIS
- Authoritative: Queries the same Verisign registry backend as WHOIS
Implementation detail: Python's requests library queries the standard RDAP base URL for TLDs. Query pattern:
GET https://rdap.verisign.com/com/v1/domain/queenof{city}.com
Response handling is trivial—HTTP status code is the authoritative answer. This eliminates parse fragility and retry logic.
Architecture: Modular Checker Scripts
We built three specialized checker scripts in the /Users/cb/icloud-jada-ops/ticket-runner/ directory:
check_queenof_domains.py– Franchise domain portfolio (arbitrary cities)check_queenof_dream.py– Dream destination cities (curated travel list)check_queenof_us.py– US port cities (domestic expansion focus)
Each script follows the same pattern:
- Define city list (hardcoded or loaded from config)
- Construct domain names via string formatting
- Query RDAP for each domain concurrently
- Aggregate results into summary (available vs. taken)
- Write markdown report to disk
Key architectural decision: Separate scripts per category rather than one monolithic checker. This allows:
- Different city lists without code changes
- Independent execution for different business units
- Clear audit trail (one report per category per run)
Orchestration: Master Check Runner
We created master_check.py to coordinate all three checkers in sequence. This script:
- Invokes all three checkers as subprocesses
- Collects exit codes and aggregates results
- Consolidates findings into a single summary report
- Enables scheduling via cron or CI/CD pipeline
Output files written to /Users/cb/icloud-jada-ops/ with timestamp suffix:
QUEEN-OF-FRANCHISE-DOMAINS-2026-06-04.mdQUEEN-OF-DREAM-DESTINATIONS-2026-06-04.mdQUEEN-OF-US-CITIES-2026-06-04.md
Probe Active Domains: Identifying Current Tenants
A secondary discovery question: Which domains are taken, and what's hosted there?
We built probe_taken.py to:
- Filter results for "taken" domains
- Attempt HTTP/HTTPS connection to each domain
- Extract HTTP headers (Server, X-Powered-By, etc.)
- Log response codes and title tags
- Build an inventory of active vs. parked domains
This reveals competitive intelligence: whether domains are actively operated, parked by speculators, or holding pages. Example:
dragonbodyguards.com – 200 OK, Apache 2.4.41, parked page
queenofsandiego.com – 200 OK, nginx, active WordPress site
Output written to QUEEN-OF-TAKEN-DOMAINS-2026-06-04.md with HTTP fingerprints and status summaries.
Data Flow & Reporting
Input sources:
- Hardcoded city lists in each script (no external dependencies for data)
- Ticket details fetched from
state.json(iCloud Jada ops board)
Query flow:
- Each script iterates cities → constructs domain → queries RDAP (via HTTP GET)
- Responses aggregated by status (available, taken, error)
- Results written as markdown for human readability and git-friendly diffs
Output destinations:
- Markdown files in ops directory (committed to git for audit trail)
- Ticket system updated with summary findings (reporter adapter integration)
Key Technical Decisions
1. RDAP over WHOIS: HTTP status codes are simpler to handle than WHOIS text parsing, and rate-limiting is more predictable. RDAP is purpose-built for high-volume automated queries.
2. Modular scripts: Three separate checkers instead of one monolithic tool. This provides flexibility for different business contexts (dream destinations vs. US focus) and clearer separation of concerns.
3. Markdown output: