Firecrawl renders a page the way a browser does, so it works on sites that return nothing useful to a plain fetch. It reads one page, maps every URL on a site, or crawls the lot, and gives back clean text the agent can reason over.
Firecrawl is the reader. Other tools find the URL; Firecrawl turns it into something worth reading.
resolve a news link and read the article behind it
turn scraped pages into structured judgements
search by meaning first, then read the winners
match scraped names to real profiles
Ask for the outcome and your agent composes the run itself. Or start from a skill, a whole pipeline it already knows end to end.
browse all skills →Every tool ships with a written playbook, and the agent loads it before the first call. Auth, rate limits, what each call costs, which actions need your approval, and the mistakes worth avoiding. It is the difference between an agent that knows the tool and one that guesses at it.
Read the Firecrawl docs →HOW in lib/firecrawl.py. Also the project's tier-3 doc scraper (see reference/docs/*/scrape_docs.py).
https://api.firecrawl.dev · Auth: Authorization: Bearer <key> (env FIRECRAWL_API_KEY; never hardcode).scrape(url, formats=['markdown']) — render & scrape one page (sync).map(url, search=, limit=) — list all URLs on a site (use to discover endpoint/doc pages → then scrape each). This is the tier-3 doc-pipeline entrypoint.search(query, scrape_options=) — web search + optional scrape of results.extract(urls, prompt=/schema=) — LLM structured extraction.start_crawl(url) → {id}; get_crawl(id) — async multi-page crawl.Billed per scrape/crawl/extract. Read-only (no outreach side-effects) — spend awareness only.
The fallback doc/data scraper: when a tool's docs are a JS SPA (tier 3), map → scrape each page → cache → build adapter (the exact pattern used for Recruit CRM).
lib/firecrawl.pyImport: from lib.firecrawl import Firecrawl → instantiate Firecrawl() (reads key from env). Base: https://api.firecrawl.dev. Generic passthrough: request(method, path, *, params, json).
extract(urls: list[str], *, prompt: str | None = None, schema: dict | None = None, **opts) -> dict — POST /v2/extract — LLM structured extraction across URLs.get_crawl(crawl_id: str) -> dict — GET /v2/crawl/{id} — poll crawl status + collected pages.map(url: str, *, search: str | None = None, limit: int | None = None, **opts) -> dict — POST /v2/map — discover all URLs on a site (sitemap). Use to find endpoint/doc pages.scrape(url: str, *, formats: list[str] | None = None, only_main_content: bool = True, **opts) -> dict — POST /v2/scrape — render & scrape one URL. formats e.g. ['markdown','html','links'].search(query: str, *, limit: int | None = None, scrape_options: dict | None = None, **opts) -> dict — POST /v2/search — web search, optionally scraping each result.start_crawl(url: str, **opts) -> dict — POST /v2/crawl — start an async multi-page crawl. Returns {id}.