CodeVetter
← All unpacks
CodeVetter · Repo Unpack evidence

firecrawl/firecrawl

Scanned commit 556c12c9d2 dated 2026-09-21 — last upstream commit. Generated by codevetter 1.12.0 on 2026-09-22.

github.com/firecrawl/firecrawl ↗ · 1858 files · 13.8 MB

--- 🔥 Firecrawl The API to search, scrape, and interact with the web at scale.

Deep analysis by swe-2 via the devin CLI on 2026-09-22 (runtime not recorded) — every claim below links to its cited source files.

Overview

Firecrawl is a self-hostable web-scraping API monorepo: an Express 5/TypeScript service in apps/api exposes versioned REST endpoints (/v0, /v1, /v2) that turn URLs into markdown, JSON, screenshots and more, while background workers pull scrape jobs off a custom Postgres/FoundationDB-backed queue (NuQ) and run a waterfall of pluggable fetch engines (index cache, fire-engine Chrome CDP, Playwright microservice, plain fetch, PDF/document/image parsers). Billing (Autumn), auth (Supabase-backed API keys plus a keyless free tier), rate limiting (Redis), job state (Bigtable), and a web index cache (GCS + Postgres) are all first-class subsystems. Nine language SDKs, a Playwright sidecar, a Go html-to-markdown service, and a test-site app round out the monorepo.

System map

The core product is apps/api, an Express 5 server (src/index.ts) plus a family of worker processes spawned by a supervisor script (src/harness.ts). Jobs flow through NuQ, a bespoke queue layered on Postgres (apps/nuq-postgres/nuq.sql) with an experimental FoundationDB backend and RabbitMQ/PG-listen completion signaling; a few legacy BullMQ queues remain for LLMs.txt, deep-research and billing. Persistence is split across Redis (crawl state, rate limits, auth cache), Postgres via Drizzle (teams/API keys/Supabase), Bigtable (job state, index metadata), GCS (index documents, screenshots, logs) and ClickHouse (request logs). Scraping itself is delegated to a quality-ordered engine registry in scraper/scrapeURL/engines. Everything is configured through a single Zod schema in src/config.ts and deployed as Docker images via docker-compose.yaml and GitHub Actions.

Feature catalog

The v2 API (routes/v2.ts) is the primary surface: scrape, batch scrape, crawl (+status/errors/cancel/websocket), map, search (+developer/research proxies), extract/agent jobs, parse (multipart upload), browser/interact sessions, monitors, Slack integration, team usage/SIEM/threat-protection administration, and keyless free-tier endpoints. v1 mirrors the core endpoints (scrape/crawl/map/extract/search/deep-research/llms.txt) and v0 is a thin deprecated shim. Every mutating endpoint passes through the same middleware chain: authMiddleware (API key, OAuth, MCP delegated credential, or keyless), countryCheck, checkCreditsMiddleware (Autumn), blocklistMiddleware, and optionally idempotencyMiddleware.

All 13 feature catalog claims →

Data flow

Inbound JSON is validated by Zod schemas in controllers/v2/types.ts, then the request is stamped with team/org identity (ACUC), credits are checked against Autumn, and the job is either executed inline (sync scrape) or persisted as a NuQ row. The scrapeURL pipeline rewrites/permutes the URL, consults the blocklist, robots.txt, safe-mode and threat-protection policy, then walks a quality-ordered engine waterfall; each engine returns raw HTML which is normalized (removeUnwantedElements), converted to markdown (Go native lib or HTTP service), and passed through transformers (LLM extract, JSON, screenshots, change tracking) and postprocessors. Results are persisted to Bigtable job state, indexed to GCS+Postgres, billed per-feature, logged to PubSub/ClickHouse, and returned synchronously or delivered via webhook.

All 13 data flow claims →

Behavior traces

Three flows were traced end-to-end. Startup: harness.ts supervises containers and child processes, then index.ts initializes blocklist/engine-forcing/exchange catalog and mounts routers. Sync scrape: middleware chain → scrapeController → semaphore → processJobInternal → startWebScraperPipeline → scrapeURL → engine waterfall → transforms → billing/logging → Document. Crawl: crawlController persists Redis crawl + NuQ group, enqueues a kickoff job, and workers discover links, enqueue child single_urls jobs, track completions via addCrawlJobDone and finish via crawl-logic.

Testing signals

Tests run under Vitest (vitest.config.ts, globals on, 120s timeouts, junit output) with ~112 test files under src/__tests__ plus colocated *.test.ts units. The dominant pattern is 'snips' — end-to-end tests hitting a live API brought up by `pnpm harness` — gated by env flags (TEST_SUITE_SELF_HOSTED, OPENAI_API_KEY, SEARXNG_ENDPOINT, PROXY_SERVER). CI (test-server.yml) runs a matrix over engine/proxy/search/ai/nuq-backend on self-hosted infra. Coverage is strong on the scrape pipeline and route surface; deep unit coverage exists for config-adjacent libs but many services/ workers have no dedicated tests.

Risk map

The highest blast radius sits in the auth/credit middleware chain and the scrapeURL pipeline: both are fail-open in places (Autumn outage, missing org_id) and carry many security gates that must run in the right order. Keyless free-tier abuse is mitigated by IPv4-only identity and Spur checks but is inherently risky. Shell-out exists in harness.ts (container commands are escaped) and via koffi FFI to a native lib. Secrets flow through env config; SIEM/webhook/ZDR paths handle sensitive customer data. Legacy BullMQ code, v0/v1 routers, and parallel PG/FDB queue backends add maintenance surface.

Extension points

The cleanest extension seams are the scrape engine registry (add an Engine string, handler, MRT and feature/quality entry), the transformer/postprocessor lists, and the route tables (v2Router wiring controllers through shared middlewares). NuQ job modes ('single_urls', 'kickoff', 'kickoff_sitemap') dispatch in processJobWithTracing, search providers chain in search/index.ts, threat-protection providers plug behind lib/threat-protection, and exchange eligibility is isolated in lib/exchange.ts. New env config goes in the Zod schema; new team flags ride TeamFlags in the ACUC.

Contributor handoff

Work happens almost entirely in apps/api. Read AGENTS.md/CLAUDE.md first — they mandate E2E 'snips' over unit tests, `pnpm harness jest` (never pnpm start), and fixing knip failures rather than bypassing hooks. Safe edit boundaries: a new engine touches only engines/* plus the registry; a new endpoint touches controllers/v2 + routes/v2.ts + a RateLimiterMode; a new transformer touches transformers/. Danger zones: the auth/credit middleware order, ZDR propagation, and anything changing job payload shape (NuQ rows in flight). Always add env config to the Zod schema and gate tests by capability flags.

Languages

LanguageFilesShare of source
TypeScript95565%
Python18212%
Markdown100docs/config
Java936%
YAML76docs/config
PHP745%
C#413%
JSON37docs/config

Start reading here

Probable source entrypoint: apps/ — inferred from the directory tree and manifest, not the upstream docs.

Source roots

apps/ (1616 files) skills/ (16 files) firecrawl-cli-skills/ (1 files)

Source layout — apps/

PathFiles
apps/ruby-sdk/32
apps/ui/30

Repository structure

Top-level pathFiles
apps/1616
examples/167
.github/45
skills/16
firecrawl-cli-skills/1
firecrawl-workflows/1
firecrawl-cli/1
firecrawl-skills/1

Docs found: AGENTS.mdCLAUDE.mdCONTRIBUTING.mdREADME.md

Package

apps/api/package.json — firecrawl-scraper-js v1.0.0, 80 declared dependencies.

@ai-sdk/anthropic@ai-sdk/deepinfra@ai-sdk/fireworks@ai-sdk/google@ai-sdk/google-vertex@ai-sdk/groq@ai-sdk/openai@ai-sdk/xai@bull-board/api@bull-board/express@clickhouse/client@dqbd/tiktoken

CI & config entrypoints

Structural health signals

Average score 6/10 across 96 analyzed source files; 67 hotspots surfaced.

These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.

Recent history