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:

  1. Define city list (hardcoded or loaded from config)
  2. Construct domain names via string formatting
  3. Query RDAP for each domain concurrently
  4. Aggregate results into summary (available vs. taken)
  5. 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.md
  • QUEEN-OF-DREAM-DESTINATIONS-2026-06-04.md
  • QUEEN-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:

  1. Filter results for "taken" domains
  2. Attempt HTTP/HTTPS connection to each domain
  3. Extract HTTP headers (Server, X-Powered-By, etc.)
  4. Log response codes and title tags
  5. 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: