Screaming Frog Warehouse Loader
Normalizes Screaming Frog SEO Spider CSV exports (internal_all, response_codes, directives, all_inlinks) into one stabl…
Updated
Use this skill
$ npx skills add seoskills.sh/screaming-frog-warehouse-loaderAbout this skill
Screaming Frog Warehouse Loader is a Tooling Integrations skill for AI agents, published in the seoskills.sh catalog. Reach for it when your work involves ahrefs, Semrush, Screaming Frog, Moz, and Search Console workflows. 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
Screaming Frog Warehouse Loader
AGENT ROLE: Autonomous crawl-ingestion agent. Read the Screaming Frog CSV exports from a run directory, normalize them into the stable warehouse schema, diff against the previous run's row_hashes, emit DDL + a MERGE plan, and (when asked) stream only the changed rows into BigQuery. Emit the JSON in references/output.schema.json. Stateful across runs via row_hashes.
OBJECTIVE
Convert a Screaming Frog crawl into append-only warehouse rows with a per-URL row_hash, so each run inserts only new/changed URLs plus tombstones for removed ones, and audits query crawl history in SQL instead of re-crawling. Deterministic normalization; incremental, idempotent load.
INPUTS
export-dir(REQUIRED): directory holding the SF CSV exports.internal_allis mandatory;response_codes,directives,all_inlinksare merged when present.previous(OPTIONAL): the prior run's output JSON (itsrow_hashesmap drives the diff). Absent on first run (baseline).run-id(OPTIONAL, default today's date): stamped on every row; part of the idempotentinsertId.dialect(OPTIONAL, defaultbigquery):bigqueryorpostgres— shapes the emitted DDL/MERGE.table(OPTIONAL, defaultseo_wh.crawl_pages).load(OPTIONAL flag): actually stream incremental rows into BigQuery.max-rows(OPTIONAL, default 200000): size guard on rows parsed and loaded.
AUTHENTICATION (BigQuery, only when --load)
Default transform-only mode needs NO credentials (parse, diff, emit DDL/MERGE).
- IF
--loadANDdialect=postgresTHEN STOPerror.code="LOAD_UNSUPPORTED_STDLIB"(Postgres needs a driver; run the emitted SQL via your DB tool). - IF
--loadANDdialect=bigqueryTHEN REQUIREGCP_ACCESS_TOKEN(a short-lived OAuth access token, e.g.gcloud auth print-access-token),BQ_PROJECT, andBQ_DATASET.- IF any is unset THEN STOP
error.code="AUTH_MISSING_WAREHOUSE_CREDS". - This reference is std-lib-only and cannot sign a service-account JWT; supply a bearer access token, not a key file.
- IF any is unset THEN STOP
- IF the token is rejected THEN STOP
error.code="AUTH_INVALID_TOKEN"(401).
EXPECTED TOOL CALLS
- Transform + diff only:
scripts/warehouse_loader.py --export-dir ./sf_export --run-id 2026-09-15 --previous prev.json. - Incremental load: append
--load(BigQuery target); the script creates the table if missing, thentabledata.insertAllthe changed rows.
PROCEDURE (deterministic)
STEP 1 — DISCOVER exports in export-dir by fuzzy basename (internal_all / response_codes / directives / all_inlinks). IF internal_all absent THEN STOP error.code="REQUIRED_EXPORT_MISSING".
STEP 2 — NORMALIZE: merge the exports into one row per URL following priority internal_all > response_codes > directives (first non-empty value wins). Map SF headers to stable columns, coercing ints/floats. Strip URL fragments.
STEP 3 — ENRICH from all_inlinks: count distinct linking sources per destination and the top inbound anchors.
STEP 4 — HASH: compute row_hash = sha1(HASH_FIELDS) per URL (status, indexability, canonical, redirect, on-page, robots) — the ingested timestamp is excluded so unchanged pages hash identically.
STEP 5 — DIFF vs previous.row_hashes: partition URLs into new / changed / removed / unchanged. First run → status="baseline".
STEP 6 — BUILD incremental payload = new + changed rows, plus a present=false tombstone row per removed URL. Emit ddl (partitioned by ingest day, clustered by url) and an illustrative merge_sql for the current-state view.
STEP 7 — IF --load: ensure the table (idempotent, 409 = already exists), then insertAll in batches of 500 with insertId = row_hash:run_id so re-runs never double-insert. Report loaded/failed.
RATE LIMITS & ERROR HANDLING
- BigQuery
429/5xx→ exponential backoff2^attempt(max 5) then return the HTTP code on the batch;401→ STOPAUTH_INVALID_TOKEN;409on table create → treat as success. - Streaming inserts are paced (
sleep 0.2between 500-row batches) to stay under the insert quota; effective concurrency 1. - Partial insert errors are counted per row (
rows_failed) rather than aborting the run.
MISSING / INSUFFICIENT DATA
- First run (no
previous) →status="baseline"; every URL is "new", nothing is diffed as changed. - IF a merged CSV lacks a mapped column THEN that field is
null(never fabricated);all_inlinksabsent →inlinks_enriched=false. - IF
max-rowsis hit THENtruncated=trueand the run reports it; narrow the crawl or raise the cap rather than trusting a partial diff. - Zero parsed URL rows →
status="no_data"(not an error).
OUTPUT
One JSON object per references/output.schema.json. row_hashes MUST be persisted and passed back as the next run's --previous.
FILES
scripts/warehouse_loader.py— CSV normalization, run diff, DDL/MERGE emission, idempotent BigQuery load.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 Tooling Integrations
firecrawl-agent
Autonomous multi-page extraction into structured JSON. Use when the user wants website data matching a schema — pricing tiers, product listings — beyond a single-page scrape.
firecrawl-seo-audit
Audit a website's SEO with Firecrawl. Use when the user asks for an SEO audit, metadata and heading review, sitemap/site-structure analysis, keyword opportunities, competitor SERP comparison, or prioritized search optimization recommendations.
seo-google
Google SEO APIs: Search Console (Search Analytics, URL Inspection, Sitemaps), PageSpeed Insights v5, CrUX field data with 25-week history, Indexing API v3, and GA4 organic traffic. Provides real Google field data for Core Web Vitals, indexation status, search performance, and organic traffic trends. Use when user says "search console", "GSC", "PageSpeed", "CrUX", "field data", "indexing API", "GA4 organic", "URL inspection", or "real CWV data".
seo-project-setup
Populate a project's shared OpenSEO context — site scope, goals, positioning, competitors, key pages, and preferences — plus MCP checks and Search Console intake.
seo-flow
FLOW framework integration: evidence-led SEO using the Find → Leverage → Optimize → Win loop. Surfaces stage-specific AI prompts from the FLOW knowledge base (41 prompts, CC BY 4.0). Use when user says "FLOW", "FLOW framework", "seo flow", "evidence-led SEO", "find leverage optimize win", or wants stage-specific SEO prompts.
GSC Bulk Export Manager
Validates that Search Console's daily Bulk Data Export to BigQuery is configured, then runs partitioned, parameterized…