Firecrawl

raw JSON →
4.21.0 verified Tue May 12 auth: no python install: verified quickstart: verified

Web scraping API for LLMs — converts any website to clean markdown. Current version is 4.21.0 (Mar 2026). Two separate PyPI packages: firecrawl-py (official SDK) and firecrawl (different package). Class renamed from FirecrawlApp to Firecrawl in v2. Method names changed: scrape_url() → scrape(), crawl_url() → crawl(). Extreme API churn — 0.x to 4.x in one year.

pip install firecrawl-py
error ModuleNotFoundError: No module named 'firecrawl'
cause This error typically occurs because the incorrect PyPI package (`firecrawl` instead of `firecrawl-py`) was installed, or a local Python file is named `firecrawl.py`, leading to a circular import.
fix
Ensure you have installed the official SDK using pip install firecrawl-py. If you did, check if your Python script is named firecrawl.py and rename it to something else (e.g., my_firecrawl_script.py) to avoid import conflicts.
error AttributeError: 'Firecrawl' object has no attribute 'scrape_url'
cause The method names `scrape_url()` and `crawl_url()` were deprecated and renamed to `scrape()` and `crawl()` respectively in `firecrawl-py` SDK versions 2.0 and later.
fix
Update your code to use the new method names: use firecrawl.scrape() instead of firecrawl.scrape_url() and firecrawl.crawl() instead of firecrawl.crawl_url().
error ImportError: cannot import name 'FirecrawlApp' from 'firecrawl'
cause The main client class in the `firecrawl-py` SDK was renamed from `FirecrawlApp` to `Firecrawl` in version 2.0. Older code attempting to import `FirecrawlApp` will fail with newer SDK versions.
fix
Update your import statement and class instantiation: from firecrawl import Firecrawl and firecrawl = Firecrawl(api_key="...").
error 401 Unauthorized
cause This HTTP status code indicates that the request could not be authenticated, typically due to a missing, incorrect, or expired API key.
fix
Obtain a valid API key from firecrawl.dev and ensure it is correctly set as the FIRECRAWL_API_KEY environment variable or explicitly passed to the Firecrawl constructor: Firecrawl(api_key="fc-YOUR_API_KEY").
breaking FirecrawlApp class renamed to Firecrawl in v2.0. from firecrawl import FirecrawlApp raises ImportError. All v1 tutorial code is broken.
fix Replace: from firecrawl import FirecrawlApp → from firecrawl import Firecrawl. Replace: FirecrawlApp(api_key=...) → Firecrawl(api_key=...)
breaking Method names changed in v2: scrape_url() → scrape(), crawl_url() → crawl(), check_crawl_status() → get_crawl_status(). All old method calls raise AttributeError.
fix Update all method calls: app.scrape_url(url) → firecrawl.scrape(url, formats=[...]), app.crawl_url(url, params) → firecrawl.crawl(url, ...)
breaking Extreme version churn: 0.x → 1.x → 2.x → 3.x → 4.x all within ~1 year. Each major version has breaking API changes. Code from tutorials more than a few months old is likely broken.
fix Pin exact version in requirements.txt. Check GitHub releases before upgrading.
gotcha pip install firecrawl installs a DIFFERENT package — not the official Firecrawl SDK. The correct install is pip install firecrawl-py.
fix Always use pip install firecrawl-py. The import is still from firecrawl import Firecrawl.
gotcha API response fields use camelCase in the Firecrawl REST API (sourceURL, ogTitle) but the Python SDK auto-converts to snake_case (source_url, og_title). Raw API response and SDK response field names differ.
fix Use SDK snake_case field names: result.metadata.source_url not result.metadata.sourceURL.
breaking The Firecrawl client requires an API key for initialization. If the `FIRECRAWL_API_KEY` environment variable is not set, or the `api_key` argument is not explicitly passed to the `Firecrawl` constructor, a `ValueError: No API key provided` will be raised.
fix Ensure the `FIRECRAWL_API_KEY` environment variable is set with your Firecrawl API key, or pass the API key directly when initializing the client: `firecrawl = Firecrawl(api_key='YOUR_API_KEY')`.
breaking The Firecrawl SDK requires an API key for initialization. If not provided directly, it expects the `FIRECRAWL_API_KEY` environment variable to be set. Missing or empty API key will raise a `ValueError`.
fix Ensure the `FIRECRAWL_API_KEY` environment variable is set with a valid API key, or pass the `api_key` argument directly to the `Firecrawl` constructor: `Firecrawl(api_key='YOUR_API_KEY')`.
pip install firecrawl
python os / libc variant status wheel install import disk
3.10 alpine (musl) firecrawl - - 1.74s 106.6M
3.10 alpine (musl) firecrawl-py - - 1.76s 46.3M
3.10 slim (glibc) firecrawl - - 1.24s 178M
3.10 slim (glibc) firecrawl-py - - 1.24s 48M
3.11 alpine (musl) firecrawl - - 2.33s 117.0M
3.11 alpine (musl) firecrawl-py - - 2.31s 51.1M
3.11 slim (glibc) firecrawl - - 1.97s 189M
3.11 slim (glibc) firecrawl-py - - 1.95s 53M
3.12 alpine (musl) firecrawl - - 2.30s 107.6M
3.12 alpine (musl) firecrawl-py - - 2.25s 42.4M
3.12 slim (glibc) firecrawl - - 2.21s 180M
3.12 slim (glibc) firecrawl-py - - 2.19s 44M
3.13 alpine (musl) firecrawl - - 2.10s 104.1M
3.13 alpine (musl) firecrawl-py - - 2.08s 42.1M
3.13 slim (glibc) firecrawl - - 2.12s 178M
3.13 slim (glibc) firecrawl-py - - 2.04s 44M
3.9 alpine (musl) firecrawl - - 1.64s 106.4M
3.9 alpine (musl) firecrawl-py - - 1.65s 46.2M
3.9 slim (glibc) firecrawl - - 1.48s 179M
3.9 slim (glibc) firecrawl-py - - 1.52s 48M

v2+ API. scrape() for single URLs, crawl() blocks until done, start_crawl() for async.

from firecrawl import Firecrawl
from firecrawl.types import ScrapeOptions
import os

# API key from env or direct
firecrawl = Firecrawl(api_key=os.environ.get('FIRECRAWL_API_KEY'))

# Scrape single URL → markdown
result = firecrawl.scrape(
    'https://docs.firecrawl.dev',
    formats=['markdown', 'html']
)
print(result.markdown[:500])
print(result.metadata.title)

# Crawl entire site (blocking, auto-polls)
crawl = firecrawl.crawl(
    'https://docs.firecrawl.dev',
    limit=50,
    scrape_options=ScrapeOptions(formats=['markdown']),
    poll_interval=5
)
for doc in crawl.data:
    print(doc.metadata.source_url, len(doc.markdown or ''))

# Async crawl (non-blocking)
job = firecrawl.start_crawl(
    'https://docs.firecrawl.dev',
    limit=50
)
status = firecrawl.get_crawl_status(job.id)