Concepts

Choose Your Endpoint

CRW has a native /v1 API for new integrations and a /firecrawl/v2 compatibility layer for Firecrawl migrations. Pick the capability that matches your input and output.

Six verbs: scrape, map, crawl, search, extract, parse
Start here: native /v1
Extract: single URL = scrape + JSON format; many URLs = native /v1/extract

Comparison table

New to CRW? Use /v1. Use /firecrawl/v2 when migrating Firecrawl v2 SDK code or when the feature only exists on the compatibility surface, such as POST /firecrawl/v2/batch/scrape or POST /firecrawl/v2/parse.

Verb Route Input Output Use when LLM required?
scrape POST /v1/scrape A single URL Markdown, HTML, plain text, links, or raw HTML You know the exact page URL and want its content No (yes for summary format)
map POST /v1/map A domain or start URL List of URLs discovered under that origin You need to enumerate pages before scraping or crawling No
crawl POST /v1/crawl A start URL Async job — poll GET /v1/crawl/{id} for all pages You want every page under a URL scraped in one background job No (yes if you add summary to scrapeOptions)
search POST /v1/search A query string Ranked web search results, optionally with scraped content You do not have a URL — you want the web to find relevant pages No (yes for answer/summarize_results options)
extract (single URL) POST /v1/scrape A URL + prompt/schema data.json — a filled-in object You have one page and want structured fields (price, title, date…) Yes
extract (multi-URL) POST /v1/extract URLs + prompt/schema Async job — poll GET /v1/extract/{id} for a per-URL results array You want the same structure extracted across several pages in one job Yes
parse POST /firecrawl/v2/parse A PDF file upload Markdown (or JSON/summary with schema) from the document You have a local file, not a URL No (yes for summary/json formats)

Two ways to extract. For a single page, extraction is just POST /v1/scrape with formats: ["json"] + a prompt and/or jsonSchema. For multiple URLs, the native POST /v1/extract runs them as one async job and returns a per-URL results array (each URL keeps its own object; no last-write-wins merge). Both call an LLM.

Decision tree

Do you have a file (PDF) to parse?
  └─ Yes ──► Parse   POST /firecrawl/v2/parse

Do you know the exact URL(s) of the page(s) you want?
  ├─ Yes ──► Do you need structured fields (price, date, …)?
  │            ├─ Yes ──► One URL?  ──► Extract  POST /v1/scrape  (formats:["json"] + prompt/jsonSchema)
  │            │          Many URLs? ──► Extract  POST /v1/extract (async, per-URL results)
  │            └─ No  ──► Scrape   POST /v1/scrape
  └─ No  ──► Are you looking across an entire site?
               ├─ Yes ──► Do you want every page's content in one job?
               │            ├─ Yes ──► Crawl  POST /v1/crawl
               │            └─ No  ──► Map    POST /v1/map
               └─ No  ──► Search  POST /v1/search

About extract

Extract reuses the scrape route. The only difference from a plain scrape is that you add two fields to the request body:

{
  "url": "https://example.com/product/42",
  "formats": ["json"],
  "jsonSchema": {
    "type": "object",
    "properties": {
      "title":  { "type": "string" },
      "price":  { "type": "string" }
    },
    "required": ["title"]
  }
}

CRW scrapes the page and then calls an LLM with your schema to produce the data.json field in the response. Because an LLM call is involved, extraction requires either a server-side [extraction.llm] configuration (self-hosted) or a per-request llmApiKey.

Multiple URLs: POST /v1/extract

When you want the same structure from several pages, use the native async route instead of calling scrape N times:

{
  "urls": ["https://example.com/a", "https://example.com/b"],
  "prompt": "extract the product title and price",
  "schema": { "type": "object", "properties": { "title": {"type":"string"}, "price": {"type":"string"} } }
}

It returns { "success": true, "id", "status": "processing", "urls": 2 }; poll GET /v1/extract/{id} for a results array (one { url, status, data, error } per URL, in request order). Capped by crawler.max_extract_urls (default 50) since each URL triggers an LLM call. On the hosted service at api.fastcrw.com this is handled automatically.

See Extract for the full parameter reference and provider options.

Quick examples

Scrape one page as markdown:

curl -X POST https://api.fastcrw.com/v1/scrape \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com","formats":["markdown"]}'

Discover all URLs on a site:

curl -X POST https://api.fastcrw.com/v1/map \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}'

Crawl an entire site (start + poll):

# Start
curl -X POST https://api.fastcrw.com/v1/crawl \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}'

# Poll with the returned job ID
curl https://api.fastcrw.com/v1/crawl/{id} \
  -H "Authorization: Bearer YOUR_API_KEY"

Search the web:

curl -X POST https://api.fastcrw.com/v1/search \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"open source web scraping 2025","limit":5}'

Extract structured data:

curl -X POST https://api.fastcrw.com/v1/scrape \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/product/42",
    "formats": ["json"],
    "jsonSchema": {
      "type": "object",
      "properties": {
        "title": {"type": "string"},
        "price": {"type": "string"}
      },
      "required": ["title"]
    }
  }'

Parse a PDF:

curl -X POST https://api.fastcrw.com/firecrawl/v2/parse \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@/path/to/document.pdf"
  • Scraping — full scrape parameter reference
  • Map — URL discovery and filtering
  • Crawling — async crawl job management
  • Search — query options and result enrichment
  • Extract — JSON schema extraction
  • Output formats — all eight formats values