1. Free-tier limit mismatch (P0): Hero CTA says "10 Free Searches" and meta description says "10 searches/day" — but the API enforces 3/day. Misleads every visitor.
2. Stripe test mode live in production (P0): All three checkout sessions return cs_test_ prefixed URLs. Real users cannot complete payment.
3. No terms / privacy / refund pages (P0): All return 404. The site is taking Stripe payments with zero legal pages — regulatory/compliance risk, and Stripe ToS requires them.
---
No Chrome MCP was available in this session — QA was performed via curl HTTP inspection and JS bundle analysis. Screenshots were not captured. Recommend a follow-up Chrome MCP session for visual/mobile screenshots.
---
| Finding | Severity |
|---|---|
| Search API works correctly — SSE streaming, results returned for all tested strategies | PASS |
| TLD format: API requires "com" (no dot); UI labels show .com — internally consistent | INFO |
| Rate limit returns HTTP 402 with clear JSON error + upgrade_url field | PASS |
| Rate limit reset: retry-after: 21600 (6-hr rolling window). Pricing copy says "Resets every day" — technically inaccurate | P2 |
| "Buy" button links to Namecheap affiliate (namecheap.pxf.io/c/4384099/...?sharedid=snapdomain) — affiliate code present | PASS |
| Hero CTA reads "Try 10 Free Searches" but limit is 3/day. Meta description also says "10 searches/day". | P0 |
| Favorites saved to localStorage only — lost on browser data clear | P2 |
---
| Tier | Result |
|---|---|
| Credit pack ($5/50) | 303 to checkout.stripe.com/c/pay/cs_test_b1PhCr6… — REDIRECTS TO STRIPE |
| Pro ($9/mo) | 303 to checkout.stripe.com/c/pay/cs_test_b1XyP0r… — REDIRECTS TO STRIPE |
| Max ($79/mo) | 303 to checkout.stripe.com/c/pay/cs_test_b1voZcq… — REDIRECTS TO STRIPE |
| Pro Annual | 303 to /#pricing?error=not_configured&tier=pro-annual — BROKEN |
| Max Annual | 303 to /#pricing?error=not_configured&tier=max-annual — BROKEN |
All three working checkouts use cs_test_ prefix — Stripe TEST MODE. The product is publicly accessible but payments cannot complete. This is a P0 blocker.
Annual pricing: The pricing section shows static copy "All paid plans: 20% off annual (2 months free)" but there is no toggle UI and no working annual checkout routes. The promise exists; the product does not.
---
Visual mobile QA requires Chrome MCP (not available this session). Structural notes from HTML:
| Finding | Severity |
|---|---|
| Search input: flex flex-col sm:flex-row — correct vertical stack on mobile | PASS |
| Pricing grid: md:grid-cols-4 — stacks to single column below 768px | PASS |
| CTA buttons have min-h-[48px] — meets 44px tap-target requirement | PASS |
| Standard viewport meta width=device-width, initial-scale=1 | PASS |
| Hero h1 text-5xl (48px) on 375px — may cause multi-line overflow; needs visual check | P2 |
---
| Finding | Severity |
|---|---|
| Form submits to POST /api/subscribe — endpoint returns 200 with success message | PASS |
| Empty / invalid email returns 400 "Invalid email" | PASS |
| Honeypot field (name="website") present in HTML | PASS (UI layer) |
| Honeypot NOT enforced server-side — submitting website: "http://spam.com" returns 200 OK | P1 |
| No rate-limiting on /api/subscribe — same email submittable repeatedly | P1 |
| No GDPR consent checkbox | P2 |
---
| Finding | Severity |
|---|---|
| Empty search: inline error "Please enter at least one word…" | PASS |
| No strategies / no TLDs selected: inline errors | PASS |
| Rate limit exceeded: HTTP 402 + red error box + "Upgrade to Pro" link | PASS |
| Network/fetch failure: "Search failed — check your connection…" | PASS |
| No-results state: "No available domains found. Try different keywords…" | PASS |
| Stripe not_configured error banner shows personal email harnoors@gmail.com | P1 |
---
| Finding | Severity |
|---|---|
| /sitemap.xml — 404 | P1 |
| /robots.txt — 404 | P1 |
| All three checkout endpoints — 303 to Stripe (correct flow) | PASS |
| All Stripe sessions are cs_test_ — test mode keys in production | P0 |
| CSP header present and correctly configured | PASS |
| Security headers: x-frame-options: DENY, HSTS, x-content-type-options | PASS |
---
| Signal | Status |
|---|---|
| "Powered by Stripe" — footer text only, no logo | Partial |
| Stripe badge/logo image | Missing |
| Terms of Service page /terms | Missing — 404 |
| Privacy Policy page /privacy | Missing — 404 |
| Refund Policy page /refund | Missing — 404 |
| "Cancel anytime" copy in pricing | Present |
| Company name HM Tech Solutions LLC in footer | Present |
| Testimonials / social proof | Missing |
| HTTPS + HSTS | PASS |
---
| # | Issue | Where | Suggested fix |
|---|---|---|---|
| 1 | Stripe test keys in production — cs_test_ on all sessions | /api/checkout env vars | Switch STRIPE_SECRET_KEY to sk_live_, update all price IDs and webhook secret to live-mode equivalents |
| 2 | Free tier copy says 10 searches; API enforces 3 | Hero CTA, meta description, hero subtext | Change hero CTA to "Try 3 Free Searches →"; fix meta description to "3 searches/day" |
| 3 | No legal pages (terms / privacy / refund) — 404 | Missing routes | Add /terms, /privacy-policy, /refund in Next.js app router; link from footer |
| # | Issue | Where | Suggested fix |
|---|---|---|---|
| 4 | Annual pricing advertised but checkout returns not_configured | Pricing section, /api/checkout | Wire Stripe annual prices OR remove "20% off annual" copy until implemented |
| 5 | Personal email harnoors@gmail.com in production error banner | JS error state for not_configured | Replace with support@snapdomain.us or a help URL |
| 6 | Sitemap + robots.txt missing | Site root | Add app/sitemap.ts and app/robots.ts via Next.js 14 metadata API |
| 7 | Honeypot not enforced server-side on subscribe | /api/subscribe handler | Check website field; silently return 200 but skip saving |
| 8 | No rate-limiting on /api/subscribe | /api/subscribe | Add IP-based rate limit (e.g. 3 per IP per hour) |
| 9 | Stripe badge/logo missing | Footer | Add official "Payments powered by Stripe" SVG badge with link to stripe.com |
| 10 | Footer missing links to legal pages | Footer | Add terms / privacy / refund links once pages exist |
| # | Issue | Where | Suggested fix |
|---|---|---|---|
| 11 | Favorites lost on browser data clear | localStorage | Offer sign-in to persist favorites server-side (future auth feature) |
| 12 | Rate limit says "Resets every day" but header is 6-hr rolling window | Pricing copy, error message | Change copy to "Resets every 6 hours" or implement true midnight UTC reset |
| 13 | No GDPR consent on email capture | Subscribe form | Add "I agree to receive one launch email" checkbox; save consent timestamp |
| 14 | Hero h1 at 375px may overflow — needs visual check | Hero section | Visual QA via Chrome MCP; reduce to text-4xl on xs if needed |
---
Source is not in F:/TITAN. All fixes must be applied in the Next.js repo. Key files to look at:
app/api/checkout/route.ts — Stripe session creation and tier routing (fix: live keys, wire annual tiers)app/api/subscribe/route.ts — email capture (fix: enforce honeypot, add rate limit)app/api/search/route.ts — search + rate limit (no changes needed)app/page.tsx — hero CTA copy (fix: 10 → 3)app/layout.tsx or app/page.tsx metadata — meta description (fix: 10 → 3)app/sitemap.ts, app/robots.ts — create theseapp/terms/page.tsx, app/privacy-policy/page.tsx, app/refund/page.tsx — create theseTo switch Stripe to live mode: replace STRIPE_SECRET_KEY env var with sk_live_..., update all hardcoded price IDs to live-mode price IDs from the Stripe dashboard, update STRIPE_WEBHOOK_SECRET to the live webhook secret.