competitor-teardown — from URL to a full product teardown
Six stages. Scripts do the deterministic work (crawl, screenshots, HTML, geometry, wireframes, tech stack, report build); you do the judgement (interactive flows, UX critique, business model, hook/funnel). Data flows through JSON files in the output directory, so every stage can be re-run alone.
$SKILL below = the directory containing this file (~/.claude/skills/competitor-teardown).
What this produces
teardowns/<domain>/<YYYY-MM-DD>/
├── crawl.json pages[], link graph, stats, errors
├── network.json third-party hosts per page
├── techstack.json detected technologies
├── analysis.json your analysis (validated against templates/analysis.schema.json)
├── analysis.md readable twin of analysis.json
├── report.html self-contained report (screenshots + wireframes embedded)
├── report.artifact.html only with --artifact: downscaled images, < 15 MB, for publishing
├── pages/<slug>/ screenshot.png · page.html · geometry.json · meta.json · wireframe.svg
└── flows/<flow>/ NN-<step>.png from the interactive pass
Stage 0 — Prerequisites
test -d "$SKILL/scripts/node_modules/playwright" || (cd "$SKILL/scripts" && npm install && npx playwright install chromium)
Tell the user if this installs anything (≈100 MB Chromium download once).
Stage 1 — Intake
Ask only for what is missing; never block on optional items:
- URL(s) (required). Competitor name defaults to the hostname.
- "Our product" context (optional, one paragraph): who you are, your ICP, your positioning. With it,
opportunitiesbecomes comparative ("we could…"); without it, it is generic.
Set OUT=teardowns/<host-without-www>/<YYYY-MM-DD> relative to the current working directory. State the default scope out loud: whole site, same host, no page cap. Flags the user can add: --max-pages N, --depth N, --exclude '<regex>', --include-subdomains, --concurrency N (default 3), --delay ms (default 500), --resume.
Stage 2 — Crawl
node "$SKILL/scripts/crawl.mjs" <url> [<url>…] --out "$OUT" [flags]
- Watch stderr: one line per page
[n/—] /path ok 1.8sorFAIL <reason>. - If more than ~150 pages are discovered (crawl.json is written only at the end, so judge from the counter) and the crawl is still going after a few minutes, tell the user and offer
--max-pages/--exclude/--depth 2. Do not kill the crawl unilaterally — whole-site is the chosen default. - Interrupted? Re-run the same command with
--resume; pages that already havemeta.jsonare skipped. - Exit code 1 means zero pages succeeded — see Failure modes.
Stage 3 — Wireframes and tech stack
node "$SKILL/scripts/wireframe.mjs" --out "$OUT" # one line per page: slug: nav › hero › features › …
node "$SKILL/scripts/techstack.mjs" --out "$OUT" # prints category name (confidence)
wireframe.mjs writes pages/<slug>/wireframe.svg and adds sections[] into each geometry.json. The classifier is heuristic — you will correct types in Stage 5 from the screenshots.
Stage 4 — Interactive flows (optional, Playwright MCP)
Read $OUT/crawl.json and pick at most 6 flows that a static crawl cannot show: signup start, pricing monthly/annual toggle, "book a demo" modal, onboarding steps reachable without login, in-site search, chat widget, interactive demo. For each:
mcp__plugin_playwright_playwright__browser_navigateto the page.- Act with
browser_click/browser_type/browser_select_option. browser_take_screenshotafter each meaningful step, saving to$OUT/flows/<flow-slug>/NN-<step>.png(create the directory first).- Note what changed.
Never enter real credentials or submit forms that create accounts or send messages. Skip this stage entirely when nothing interactive matters (docs sites, brochure sites) and say so.
Stage 5 — Analysis (you)
- Read
$OUT/crawl.json. Choose 5–12 key pages perreferences/ux-section-taxonomy.md§2 (landing, pricing, signup/demo, strongest feature/solution pages, about, one docs/blog index). - For each key page: Read
pages/<slug>/meta.jsonand thesectionsingeometry.json; viewscreenshot.pngandwireframe.svg(Read the image files). Confirm/correct section types, write notes and the five-score critique perreferences/ux-section-taxonomy.md§3–4. - Site-level: build
siteMapfromcrawl.json.pages[]; writeuiArchitecturefrom what repeats across screenshots; decodebusinessModelperreferences/business-model-patterns.md; writehookAndFunnelperreferences/hook-and-funnel.md; mergetechstack.json.detected[]with your own reading intotechStack[](keep detector rows, add inferred ones asconfidence: "low"); writeopportunities(quick wins / medium term / strategic); addflows[]from Stage 4. - Optional: invoke the
design-craftskill (AUDIT mode) on 1–3 key screenshots and fold its findings intocritique. - Write
$OUT/analysis.jsonconforming to$SKILL/templates/analysis.schema.json(all nine top-level keys required; scores are integers 1–5) and$OUT/analysis.mdwith the same content in prose.
Evidence rule: every strength, weakness, funnel item, and persuasion pattern cites slug § section-type or flows/<slug>/NN. Inferences are labelled as inferences.
Stage 6 — Report
node "$SKILL/scripts/build-report.mjs" --out "$OUT" # → report.html
If it exits 1 with analysis.json invalid: lines, fix those fields and re-run. Then open "$OUT/report.html" (macOS) and tell the user the path.
Offer to publish. If yes:
node "$SKILL/scripts/build-report.mjs" --out "$OUT" --artifact # → report.artifact.html (< 15 MB or fails)
then use the Artifact tool on report.artifact.html with favicon 🔍 (artifacts are private by default). If the artifact build fails on size, trim pages[] to the most important 8 and drop flow screenshots, rebuild.
Recap format
End with: pages crawled / failed; the 5 most important findings (one line each, with evidence); the report path and the Artifact URL if published; what was skipped and why.
Failure modes
| Symptom | What to do |
|---|---|
Every page FAIL HTTP 403 or a Cloudflare/“verify you are human” page in screenshots |
Bot protection. Retry with --concurrency 1 --delay 2000; if still blocked, tell the user and fall back to the Playwright MCP for a handful of pages (headed browsers often pass). |
| Only the seed page crawled on a JS app | Links are read from the rendered DOM, so this usually means client-side routing with no <a href>. Use Stage 4 for navigation, or pass more seed URLs. |
| Thousands of pages (blog/docs/pagination) | `--exclude '?page= |
| Screenshot cut off or repeating header | Page > 20 000 px (capped) or a sticky element the hider missed; note it in wireframeNotes. |
analysis.json invalid |
The message lists $.path: problem lines; fix exactly those. |
report.artifact.html > 15 MB |
Fewer pages[], fewer flow screenshots. |
Re-running pieces
- New analysis, same crawl: edit
analysis.json, re-run Stage 6. - Crawl more pages later: Stage 2 with
--resume, then Stages 3 and 6. - Extend tech detection: add a row to
scripts/lib/signatures.mjs. Extend section types:scripts/lib/sections.mjs+ theenumintemplates/analysis.schema.json.