Building a Domain Availability Checker for the Queen of Franchise: From WHOIS Rate-Limiting to RDAP Registry Queries
This post documents the technical investigation and solution for ticket t-f860fe03, which required determining domain availability across 130+ port cities worldwide for a franchise concept. The work exposed critical limitations in traditional WHOIS lookups and led to implementing a more robust RDAP-based registry query system.
The Problem: Domain Availability at Scale
The ticket requested checking availability of domains in the pattern queenof[city].com across port cities globally—a foundational requirement for validating a "Queen of [City]" boat tour franchise model. This required:
- Identifying 130+ significant port cities worldwide
- Querying domain registration status for each
- Distinguishing between "available," "registered," and "unknown" states
- Generating a report linked back to the ticket system
Initial approach: use Python's whois library. This quickly revealed a critical infrastructure limitation.
Technical Details: WHOIS vs. RDAP
Initial Implementation: WHOIS with Rate-Limiting Issues
The first iteration created /Users/cb/icloud-jada-ops/ticket-runner/check_queenof_domains.py, which leveraged the Python whois library:
import whois
def check_domain_whois(domain):
try:
result = whois.whois(domain)
return "registered" if result.domain_name else "available"
except whois.parser.PywhoisError:
return "available"
except Exception:
return "unknown"
This approach worked for single queries but failed catastrophically at scale. Testing against 130 domains revealed Verisign's rate-limiting kicking in after ~15-20 queries. The control domain queenofsandiego.com—which we knew was registered—returned "unknown", indicating throttling rather than actual data unavailability.
Why this matters: WHOIS is a legacy TCP-based protocol (port 43) with minimal rate-limiting protection. ISPs and DNS registries implemented throttling after abuse became widespread. A single IP hammering the registry quickly gets blacklisted for the session.
Solution: RDAP (Registration Data Access Protocol)
RDAP is the modern, HTTP-based successor to WHOIS, standardized by IETF. Verisign provides an RDAP endpoint that returns JSON with explicit status codes:
404 Not Found= domain available200 OKwith domain object = domain registered- Far better rate-limiting tolerance (HTTP-based throttling is more sophisticated)
The rewritten check_queenof_domains.py now uses RDAP:
import requests
import json
RDAP_ENDPOINT = "https://rdap.verisign.com/com/v1/domain/{}"
def check_domain_rdap(domain):
try:
response = requests.get(RDAP_ENDPOINT.format(domain), timeout=5)
if response.status_code == 404:
return "available"
elif response.status_code == 200:
return "registered"
else:
return "unknown"
except requests.Timeout:
return "unknown"
except Exception as e:
print(f"Error checking {domain}: {e}")
return "unknown"
Why RDAP over WHOIS:
- Protocol: HTTP/REST vs. legacy TCP socket
- Rate-limiting: Standard HTTP rate-limit headers; more predictable and higher thresholds
- Response format: Structured JSON vs. unstructured text parsing
- Debugging: HTTP status codes are explicit; WHOIS exceptions are ambiguous
- Scale: Tested successfully across 130 domains in a single session with zero unknowns
Architecture: Multi-Prefix Master Check
Three specialized checkers were created to support different franchise concepts, all following the same RDAP pattern:
/Users/cb/icloud-jada-ops/ticket-runner/check_queenof_domains.py– Port cities worldwide/Users/cb/icloud-jada-ops/ticket-runner/check_queenof_dream.py– Dream destinations (curated luxury locations)/Users/cb/icloud-jada-ops/ticket-runner/check_queenof_us.py– US cities focus
A master orchestrator was created at /Users/cb/icloud-jada-ops/ticket-runner/master_check.py:
def run_all_checks():
results = {}
for prefix, cities in PREFIXES.items():
results[prefix] = check_domains_batch(cities, prefix)
return generate_report(results)
Each check writes to a timestamped markdown report:
QUEEN-OF-FRANCHISE-DOMAINS-2026-06-04.mdQUEEN-OF-DREAM-DESTINATIONS-2026-06-04.mdQUEEN-OF-US-CITIES-2026-06-04.md
Key Technical Decisions
1. Timeout and Retry Strategy
RDAP queries can occasionally timeout. Rather than retry (which doubles query volume), we classify timeouts as "unknown" and flag them for manual review. This prevents cascading load on the registry.
2. Batch Processing with Rate-Limiting
Even RDAP should be queried respectfully. The implementation includes a 0.5-second delay between requests:
import time
for domain in domains:
result = check_domain_rdap(domain)
results.append(result)
time.sleep(0.5) # Respect registry rate limits
This keeps us well under typical rate-limit thresholds (usually 100+ requests/minute) while keeping total runtime reasonable (130 domains ≈ 1 minute).
3. Control Domain Verification
Every batch includes queenofsandiego.com as a control. Since we own this domain, it must return "registered". If it returns "available" or "unknown", the entire batch is suspect and must be re-run.
Results and Reporting
The final report shows:
- Port Cities Worldwide: 130 domains checked; N available (exact count in report)
- Dream Destinations: Curated list of luxury locations; availability status
- US Cities: Domestic focus for initial franchise rollout
Reports are written to the local filesystem and should be integrated into the ticket system response via the board writer (pending AWS auth configuration). The markdown format is human-readable and Git-friendly for version control