AI domain intelligence that finds every brand gap before a squatter does
Visit Product ↗Most brands discover they've been cybersquatted the wrong way. A customer emails to say they got a phishing link from yourcompany-careers.co.uk. Legal receives a cease-and-desist from a fake storefront at yourcompanyshop.de. A journalist finds a counterfeit site ranking above the real one in Germany. By the time the brand team finds out, the damage — stolen credentials, fake job applications, eroded trust — is already underway.
The economics of inaction are brutal. Registering a domain proactively costs $12–$20. Reclaiming a cybersquatted one through UDRP arbitration costs $1,500–$5,000 and takes 2–3 months — assuming you win. The problem isn't that brand teams don't care. It's that no tool existed to make proactive protection fast, cheap, and accessible without an IP attorney. BrandGuard is my attempt to fix that.
Before writing a line of code, I spent time mapping the actual problem space.
The status quo is reactive by design. When I asked brand managers how they currently discover domain threats, the answers were consistent: customer complaints, Google Alerts that fire too late, and annual audits by IP attorneys. None of those workflows catch threats before they cause harm.
The existing alternatives all have the same fatal flaw — they're either too slow, too expensive, or too manual to use proactively:
The gap I identified: No tool existed that could take a company name, understand its global footprint, enumerate every plausible domain variant, check live registration status for all of them, and return a prioritised action list — in minutes, for free.
The damage model is asymmetric. One cybersquatted domain in a key market can enable a phishing campaign targeting thousands of customers, a fake recruitment site that poisons your employer brand, or counterfeit product sales that generate customer service chaos. The attacker pays $12 to register it. The brand pays $5,000 and three months of lawyer time to get it back.
Three distinct personas emerged from my research, each with a different relationship to the same problem:
| Persona | Role | Core Pain | What They Need |
|---|---|---|---|
| Brand Manager | Owns brand consistency across markets | Discovers threats reactively via customer complaints | Clear risk language, one-click registration actions |
| IP / Legal Counsel | Manages trademark portfolio and disputes | Manual audits are expensive and infrequent | Exportable evidence, raw RDAP data for UDRP filings |
| Startup Founder | Protecting brand while scaling internationally | Doesn't know which domains to register before a new market launch | Fast checklist before announcing the expansion |
The key insight from this exercise: all three share the same underlying problem — reactive discovery — but they need different output formats. The brand manager needs a traffic-light risk summary and a "Register Now" button. Legal needs the full RDAP registrar and expiry data for a cease-and-desist. The founder needs a 10-minute pre-launch checklist. One report has to serve all three.
I almost didn't build this. The scope felt large — you'd need a database of every company's trademark portfolio, their operating countries, their brand variations, and live domain status for hundreds of combinations. That's a data company, not a weekend product.
Three realisations changed my assessment:
1. AI already knows your brand. An LLM like Claude has absorbed enormous amounts of information about most companies — their geographic footprint, trademark registrations, product lines, slogans, common misspellings. I don't need a proprietary database. I just need to ask the right questions in the right sequence.
2. RDAP makes live domain checking completely free. The Registration Data Access Protocol is a public, keyless API standard — structured JSON responses from every major TLD registry. No API key. No subscription. No rate limit that matters at this scale. It's the modern replacement for WHOIS (which returns unstructured text and often requires a paid API). The entire domain-checking layer costs exactly $0.
3. The output must be a Top 10 list, not a spreadsheet. Users don't need 300 rows of domain data. They need "register these 10 domains, starting with this one, here's the link." The product's value is the prioritisation and the action — not the data. Any tool that stops at the data layer has missed the point.
With the problem clear and the approach validated, I wrote a PRD before touching any code. The discipline of forcing explicit goal definitions and non-goals before building pays off every time.
| # | Goal | Metric | Target |
|---|---|---|---|
| G1 | Help brand teams discover gaps they didn't know existed | Avg. new gaps found per Fortune 500 scan | > 20 gaps |
| G2 | Reduce time from "brand concern" to actionable report | Company name entry → full report | < 5 minutes |
| G3 | Make domain protection accessible without IP attorneys | % of users who act on results without legal help | > 80% |
| G4 | Drive immediate registration of HIGH risk gaps | % of HIGH risk gaps where "Register Now" is clicked | > 40% |
| G5 | Build trust through transparency | Users who understand why each domain is flagged | > 90% |
Explicit non-goals keep scope from expanding indefinitely. For v1, I ruled out:
| ID | Requirement | Acceptance Criteria |
|---|---|---|
| P0-01 | User enters company name and starts a scan | Scan starts within 2s; scan ID returned immediately |
| P0-02 | 7 AI agents run in a 4-phase orchestrated pipeline | All 7 agents complete per the Phase 1→4 dependency graph; none skipped |
| P0-03 | RDAP status check for every generated domain | Every domain receives a status: available / registered / unknown |
| P0-04 | Risk level (HIGH / MEDIUM / LOW) for each domain | HIGH = exact brand match in a key market; every record has a riskLevel |
| P0-05 | Top 10 Priority Actions table with "Register Now" links | GoDaddy pre-filled URLs open correctly in new tab |
| P0-06 | Live dashboard streams agent progress in real time | SSE events update agent card status within 500ms of server event |
| P0-07 | Demo mode loads pre-computed Nike data — no API key needed | /api/demo/nike returns in <200ms; full results render correctly |
| P0-08 | Rate limiting on RDAP calls (max 10 req/sec) | Token bucket enforces ≤10 concurrent RDAP requests; no 429s from registries |
| P0-09 | Each agent handles API failures gracefully with retry | 3 retry attempts with exponential backoff; failure logged without crashing the scan |
| P0-10 | Full results table is sortable and filterable | Sort on any column; independent filters for Status, Risk, Country, TLD Type |
This was the most important design decision in the entire project. The naive approach — one big prompt asking Claude to "analyse brand X's domain exposure" — doesn't work reliably. The output is too long, the reasoning gets muddled, and you can't debug which part failed.
The key insight is that brand domain analysis is a dependent knowledge graph, not a single question. Each stage's output is the input to the next:
Brand name → Who are you? → Where do you operate? → What are you trademarked as?
↓
What domains should exist?
↓
Which ones actually exist? + Who's squatting your brand?
↓
What should you do first?
This maps cleanly to 7 agents across 4 phases:
⚡ ~60% faster than running all 7 agents sequentially — Phases 1 and 3 use Promise.all() to run their agents in parallel
Why not one mega-prompt? Three reasons drove the multi-agent design:
Promise.all(). Running all 7 sequentially would take roughly 3× as long.The most important architecture insight: Agent 5 — the domain status checker — uses zero AI tokens. The risk classification logic (assignRisk, classifyOwner, estimateCost) is pure deterministic JavaScript. This is the most data-intensive step (checking hundreds of RDAP responses), and removing the LLM from it dramatically reduces cost and latency.
The right tool for pattern-matching structured data isn't an LLM. It's a function. Save your AI tokens for the reasoning that actually requires intelligence.
Here's how the risk scoring works for every domain the scanner checks:
Every technology choice was a deliberate decision, not a default. Here's the table I worked through before starting:
| Decision | Chosen | Rejected | Reason |
|---|---|---|---|
| AI model | Claude Sonnet + Gemini / Groq | Fine-tuned model | LLM general knowledge of companies is sufficient; no training data needed |
| Domain lookup | RDAP (free, structured JSON) | WHOIS (unstructured text, paid) | RDAP is the modern standard; returns clean JSON that's straightforward to parse |
| Streaming | Server-Sent Events (SSE) | WebSockets | Scans are unidirectional — server pushes, browser never sends updates back. SSE is simpler, no upgrade handshake, native browser EventSource API |
| Frontend | Vanilla HTML / CSS / JS | React, Next.js | Zero build step. Ships in seconds. Fully maintainable by one person. No framework overhead for a single-page app |
| State management | In-memory Map + EventEmitter | Redis, Postgres | Zero infrastructure for v1. The tradeoff (state lost on restart, no horizontal scaling) is acceptable for a proof-of-concept |
| Deployment | Vercel (Fluid Compute) | Railway, Fly.io, Render | Fluid Compute reuses function instances across concurrent requests — essential for SSE, where POST /scan/start and GET /scan/:id/status must share the same in-memory state |
The Vercel decision deserves elaboration. Traditional serverless — one isolated invocation per request — would break this architecture entirely. The scan is started in one HTTP request and streamed in another; they need to share the same in-memory Map. Vercel's Fluid Compute keeps a warm instance alive for the duration of a scan, making this work without any external state store.
The build sequence matters as much as the architecture. I followed one rule throughout: build from the innermost dependencies first, the entry point last.
1. services/rate-limiter.js → Pure utility, no deps. Test it first.
2. services/rdap.js → Domain lookup, depends on rate-limiter
3. services/tld-data.js → Static country→ccTLD map, no logic to test
4. services/scan-store.js → In-memory state + EventEmitter
5. services/claude.js → AI provider abstraction (Anthropic / Gemini / Groq)
6. agents/agent1–7 → Each follows the same template; Agent 5 is pure RDAP, no AI
7. orchestrator.js → Glues agents into the 4-phase pipeline
8. routes/scan.js → POST start, GET SSE stream, GET results
9. server.js → Entry point, ties everything together
10. public/index.html → Frontend — built last when the API shape is stable
11. demo/nike-demo.json → Demo data — built after schema is finalised
Building the frontend last is counterintuitive but correct. Every time I've built the UI first, I've had to refactor it when the API shape changed. Build the API until it's stable, then build the thing that calls it.
The onChunk streaming pattern is the key implementation detail for the live dashboard:
const result = await runAgent({
systemPrompt,
userPrompt,
onChunk: (text) => appendLog(scanId, 'agent1', text),
})
Every token the LLM generates is immediately forwarded to the SSE log stream. Users see the agent reasoning as it happens. This isn't just aesthetics — it builds trust. When users see the agent working through the logic ("I can see Nike operates in 38 countries, the key markets are the US, UK, Germany, Japan, Australia..."), they understand and believe the output.
Two other critical implementation decisions:
rdap.js. Any code anywhere in the codebase that calls checkDomain() is automatically rate-limited, without the orchestrator knowing or caring.The original implementation used Anthropic Claude exclusively. I added two alternatives during development:
Google Gemini for free-tier access — useful for development without API spend. The free tier (15 RPM) is frequently hit during a 7-agent scan, so the implementation added retry logic around Gemini SDK calls.
Groq became the default for the .env.example template. Groq's API serves llama-3.3-70b-versatile with extremely generous free limits (~6,000 requests/minute) and very low latency. Development cost on Groq: $0.
The abstraction in claude.js kept all 7 agents unchanged — they call a single runAgent() function and have no awareness of which provider is underneath. Switching providers is one environment variable:
AI_PROVIDER=groq # or: anthropic, gemini
Deployment went smoothly except for three issues worth documenting, because they're easy to hit and not obvious:
1. Vercel project names must be lowercase. My local directory was called "Brand Guard" (capital B, capital G, with a space). Running vercel link failed because Vercel uses the directory name as the project name and applies npm naming rules. Fix: add "name": "brandguard" explicitly to vercel.json.
{
"version": 2,
"name": "brandguard",
"builds": [{ "src": "server.js", "use": "@vercel/node" }],
"routes": [{ "src": "/(.*)", "dest": "/server.js" }]
}
2. AI_PROVIDER and the API key must both be set together. I set GOOGLE_API_KEY in the Vercel dashboard but forgot to also set AI_PROVIDER=gemini. The app defaulted to Anthropic, looked for ANTHROPIC_API_KEY, didn't find it, and failed silently on the first scan. Both variables are required.
3. Google API key format matters. Google API keys for Gemini start with AIza.... Keys generated from other Google services (service accounts, OAuth credentials) won't work with the Gemini SDK, even if they look like valid keys. Get the key specifically from Google AI Studio.
Type your brand. Add optional focus countries or extra product names. Or load the pre-computed Nike demo — no API key needed.
7 agent cards stream their reasoning in real time across 4 phases. Progress ring tracks 0/7 → 7/7 completion.
Top 10 priority actions with "Register Now" links. Sortable domain table. Competitor threats. CSV export for legal.
The product is a single-page app with three views:
1. Scan input. Enter a company name. Optionally add focus countries and extra brand/product names. Click "Run BrandGuard Scan" — or try the Nike demo instantly, no API key needed.
2. Live scanning dashboard. Seven agent cards appear, each with a status indicator, a progress bar, and a live log stream showing the agent's reasoning in real time. A progress ring tracks overall completion (0/7 → 7/7) across the four phases.
3. Results report. On completion, the report shows:
Export the full report as CSV for your legal team with one click.
v1 validates the core hypothesis: AI can map a brand's domain exposure in minutes, for free, without an attorney. The most requested extensions point clearly to v2:
v1.1 — Persistence (Next):
v2.0 — Monitoring (Future):
v1's job was to prove the concept and ship something real. It did.
The product is live at brandguard-reachmayankagarwal.vercel.app. Try the Nike demo — no account or API key needed — to see the full output in under a minute.
The source is open at github.com/reachmayankagarwal/brandguard if you want to run your own instance or adapt the multi-agent architecture for a different domain.