Site Migration Auditor
Compares a pre-migration crawl against the live post-migration site to verify that every indexable old URL 301-redirect…
Updated
Use this skill
$ npx skills add seoskills.sh/site-migration-auditorAbout this skill
Site Migration Auditor is a SEO Audits skill for AI agents, published in the seoskills.sh catalog. Reach for it when your work involves full technical and on-page audits with prioritized action plans. Install it with one command and it runs inside your own agent, so the work happens in your workflow, not a separate SEO tool.
SKILL.md
Site Migration Auditor
AGENT ROLE: Autonomous migration-integrity agent. Walk each old URL's redirect chain (never auto-follow), fetch the live destination, diff SEO signals against the pre-migration record, score parity, join clicks to size traffic-at-risk, and emit the JSON in references/output.schema.json.
OBJECTIVE
For a replatform, prove that each old indexable URL lands on the correct new page via a single clean 301, and that the new page preserves the title, canonical, structured data, and indexability that earned its traffic. Quantify what is broken and rank fixes by clicks at stake.
INPUTS
old_crawl(REQUIRED): JSON list of pre-migration page records{url, title, canonical, jsonld_types|structured_data, internal_links}(a crawler export).results-wrapped exports are unwrapped automatically.new_crawl(OPTIONAL): a post-migration crawl in the same shape; when present the destination signals are read from it instead of re-fetched.gsc(OPTIONAL): local JSON mapurl -> clicksfor traffic weighting.site(OPTIONAL): GSC property (sc-domain:example.comorhttps://example.com/) to fetch clicks live instead of a file.start/end(OPTIONAL): ISO dates for the live GSC pull. Default = last 28 complete days ending 3 days ago (GSC lag).max_urls(OPTIONAL, default 5000),max_hops(OPTIONAL, default 10),risk_threshold(OPTIONAL, default 70): parity score below which a URL is at-risk,concurrency(OPTIONAL, default 6),timeout(OPTIONAL, default 15s).
AUTHENTICATION (Search Console API — only if fetching clicks live)
- Crawling needs NO credentials. IF neither
--gscnor--siteis given THEN run without traffic weighting (has_traffic_data=false). - IF
--siteis given THEN REQUIRE envGSC_OAUTH_TOKEN(an OAuth 2.0 access token with scopehttps://www.googleapis.com/auth/webmasters.readonly). IF unset THEN STOPerror.code="AUTH_MISSING_CREDENTIALS". - Endpoint:
POST https://searchconsole.googleapis.com/webmasters/v3/sites/{urlEncoded site}/searchAnalytics/querywithdimensions=["page"],dataState="final". IF403THEN STOPerror.code="AUTH_NO_SITE_ACCESS".
EXPECTED TOOL CALLS
- Run
scripts/migration_audit.py --old-crawl old.json [--new-crawl new.json] [--gsc clicks.json | --site {property}] [--max-urls 5000] [--risk-threshold 70]. - Per old URL: manual per-hop HEAD walk (redirects disabled), then one GET of the final 200 URL when its signals are not already in
--new-crawl.
PROCEDURE (deterministic)
STEP 1 — WALK each old URL hop-by-hop with redirects DISABLED; record {url, status, location} per hop; resolve relative Location; stop on a non-3xx status, a repeat (LOOP), or max_hops (TOO_LONG).
STEP 2 — CLASSIFY the redirect into exactly one redirect_class: OK_301 (single 301/308 → 200), PERSISTED_200 (URL unchanged, still 200), CHAIN (≥2 hops), TEMPORARY_REDIRECT (302/303/307), LOOP, BROKEN_404, REDIRECT_TO_404, REDIRECT_TO_ERROR, FETCH_FAILED, OTHER. Note PROTOCOL_DOWNGRADE (https→http) as a flag.
STEP 3 — PARITY DIFF (only when the destination is 200): read the new page's title, canonical, meta robots, and JSON-LD @type set (from --new-crawl or a live GET parsed with html.parser). Start at 100 and subtract: fatal redirect → 0; CHAIN/TEMPORARY −15; title token-Jaccard < 0.6 → −15 (TITLE_CHANGED); canonical not self-referential → −15 (CANONICAL_DRIFT); pre-migration @type set not a subset of new → −15 (STRUCTURED_DATA_LOST); noindex on target → −20 (NOINDEX_ON_TARGET); internal links collapsed >60% → −10. Floor at 0.
STEP 4 — TRAFFIC-AT-RISK: join clicks by URL; a URL is at-risk when parity_score < risk_threshold OR the redirect is fatal. clicks_at_risk = clicks for at-risk URLs.
STEP 5 — EMIT the per-URL ledger, a redirect distribution, average parity, and the at_risk list sorted by clicks_at_risk then parity deficit.
RATE LIMITS & ERROR HANDLING
- Per-hop HEAD (GET fallback on 405/501). On network error retry ≤3 with backoff
2^attempt; persistent →redirect_class="FETCH_FAILED"for that URL, batch continues. - Concurrency capped at
--concurrency(default 6) worker threads across URLs. - GSC
429/5xx→ backoff2^attempt(max 5) then STOPerror.code="RATE_LIMITED".
MISSING / INSUFFICIENT DATA
- No
--gsc/--site→ parity is still scored;has_traffic_data=falseand everyclicks_at_risk=0(ranking falls back to parity deficit). NEVER invent click counts. - Destination 200 but signals unreadable → flag
TARGET_UNVERIFIABLE(do not assume parity). internal_linksdiff only runs when both crawls carry integer counts; otherwise it is skipped, not guessed.
OUTPUT
One JSON object per references/output.schema.json. No prose.
FILES
scripts/migration_audit.py— redirect walk, live signal fetch, parity diff, clicks join, risk ranking.references/output.schema.json— output contract.
Not using the CLI? Copy the SKILL.md and paste it straight into ChatGPT, Claude, or any agent.
Embed a badge
Install into your agent
More in SEO Audits
seo-audit
When the user wants to audit, review, or diagnose SEO issues on their site. Also use when the user mentions "SEO audit," "technical SEO," "why am I not ranking," "SEO issues," "on-page SEO," "meta tags review," "SEO health check," "my traffic dropped," "lost rankings," "not showing up in Google," "site isn't ranking," "Google update hit me," "page speed," "core web vitals," "crawl errors," or "indexing issues." Use this even if the user just says something vague like "my SEO is bad" or "help with SEO" — start with an audit. For building pages at scale to target keywords, see programmatic-seo.
audit
Run a comprehensive SEO audit on a website covering technical health, on-page optimization, content quality, and backlink profile. Use when the user asks for an SEO audit, site review, SEO health check, "what's wrong with my SEO", website analysis, or a full diagnostic of their site's search performance. For speed-specific issues, see audit-speed. For technical crawl/index issues only, see diagnose-seo.
seoul-subway-arrival
Look up Seoul real-time subway arrival information with the official Seoul Open Data API. Use when the user asks when a train arrives, which trains are approaching a station, or how crowded Seoul subway timing looks right now.
seo-coach
Enter a friendly OpenSEO coach mode that explains workflows, recommends next steps, and helps users use agents, web search, scraping, and MCP data effectively.
paseo
Paseo reference for managing projects, workspaces, workspace scripts, agents, schedules, and heartbeats.
paseo-handoff
Hand off the current task to another agent with full context. Use when the user says "handoff", "hand off", "hand this to", or wants to pass work to another agent.