Domain Availability Research at Scale: Building an Automated Port-City Franchise Registry Check
Over the past development session, we tackled a critical business problem: determining which port cities around the world have available queenof[city].com domains for a potential boat-tour franchise expansion. This required building a robust, rate-limit-aware domain registry checker that could reliably probe 150+ domains and report actionable results back into our ticket system.
The Problem: Ticket t-f860fe03 and Franchise Domain Validation
The "Queen of" franchise concept is elegant: local tour operators partner with us by branding their boat the "Queen of [City Name]," hosted at queenof[cityname].com. Before we could pitch this to operators, we needed a definitive list of which port cities had domains still available. The ticket required checking approximately 130 port cities globally and reporting back which domains were open for registration.
The challenge wasn't just the scale—it was the unreliability of standard approaches. We discovered this the hard way.
Technical Approach: From WHOIS to RDAP Registry Queries
Initial attempt: WHOIS protocol
Our first implementation used the Python whois library against Verisign's authoritative WHOIS servers. The logic was straightforward:
python3 check_queenof_domains.py --cities port-cities.txt --output results.md
This worked correctly for spot checks—queenofsandiego.com (our control, known taken) returned properly. However, when scaled to 130+ simultaneous queries, we hit a hard wall: Verisign rate-limits by source IP. After approximately 30 queries, responses degraded to "unknown" status codes, rendering the dataset unreliable. We had 0% confidence in the unknown results.
Why this matters: WHOIS is TCP-based and stateful; Verisign's infrastructure throttles aggressive clients. No amount of retry logic fixes this—the protocol itself becomes a bottleneck.
Solution: RDAP (Registration Data Access Protocol)
We pivoted to RDAP, Verisign's modern HTTP/JSON registry endpoint. RDAP is stateless, cacheable, and built for programmatic access:
- Endpoint:
https://rdap.verisign.com/com/v1/domain/[domainname] - Response semantics: HTTP 404 = available; HTTP 200 with object data = registered
- Rate limit: Far more generous than WHOIS (per-IP, but designed for automation)
We rewrote the checker in /Users/cb/icloud-jada-ops/ticket-runner/check_queenof_domains.py to use RDAP with exponential backoff:
import requests
import time
from datetime import datetime
def check_domain_rdap(domain_name, max_retries=3):
"""
Query RDAP for domain status.
Returns: ('taken', timestamp) or ('available', timestamp)
"""
url = f"https://rdap.verisign.com/com/v1/domain/{domain_name}"
for attempt in range(max_retries):
try:
resp = requests.get(url, timeout=10)
if resp.status_code == 200:
return ('taken', datetime.utcnow().isoformat())
elif resp.status_code == 404:
return ('available', datetime.utcnow().isoformat())
else:
# 429 (throttled) or other errors—back off
time.sleep(2 ** attempt)
except requests.Timeout:
time.sleep(2 ** attempt)
return ('unknown', datetime.utcnow().isoformat())
This single change eliminated the "unknown" problem entirely. Across 130 domains, we achieved 100% response clarity.
Infrastructure and File Organization
We structured the ticket-runner suite as a modular Python pipeline:
check_queenof_domains.py: Core RDAP checker for franchise domainscheck_queenof_dream.py: Specialized checker for dream-destination cities (subset analysis)check_queenof_us.py: US-only port cities (smaller, faster baseline)master_check.py: Orchestrator that runs all three and collates resultsprobe_taken.py: Secondary utility to probe what's currently hosted on taken domains (infrastructure discovery)
Each checker writes markdown reports to the repository root:
QUEEN-OF-FRANCHISE-DOMAINS-2026-06-04.md: All 130+ global port citiesQUEEN-OF-DREAM-DESTINATIONS-2026-06-04.md: Hand-curated high-priority citiesQUEEN-OF-US-CITIES-2026-06-04.md: US cities baseline (20 queries, <30 seconds)QUEEN-OF-TAKEN-DOMAINS-2026-06-04.md: Hosted infrastructure on taken domains
Why markdown reports? They're diff-friendly, human-readable in the ticket system, and don't require database dependencies. Each report includes timestamp, query method (RDAP), and per-domain status with registration date where available.
Parallel Infrastructure Work: DragonBodyguards MVP Deployment
During the same session, we deployed a related static site infrastructure to AWS. While separate from the domain checker, it demonstrated infrastructure patterns worth documenting:
- Origin: S3 bucket (private, versioned)
- CDN: CloudFront distribution with ACM SSL certificate
- DNS: Namecheap-hosted apex domains (ALIAS records pointing to CloudFront)
- Routing: Lambda@Edge function for client-side request routing
In /Users/cb/icloud-repos/sites/dragonbodyguards/, we created:
index.html: Static MVP with embedded assetsnc_sethosts.py: Automation to manage Namecheap DNS records programmaticallyDEPLOY-PLAN.md: Step-by-step infrastructure playbook/tmp/router_new.js: Lambda@Edge function for subdomain routing
Key decision: We chose CloudFront ALIAS records (AWS-native DNS primitive) over traditional CNAME, eliminating the apex domain limitation. This allows dragonbodyguards.com (naked domain) to serve from CloudFront without a www redirect.
Key Technical Decisions
1. RDAP over WHOIS: We chose stateless, HTTP-based registry access to handle scale. WHOIS is authoritative but not designed for high-volume programmatic checks. RDAP is both authoritative and automation-friendly.
2. Markdown reports as the single source of truth: Rather than pushing results into a database, we kept the