Firecrawl
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.
Common errors
-
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.fixEnsure 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. -
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.fixUpdate your code to use the new method names: use `firecrawl.scrape()` instead of `firecrawl.scrape_url()` and `firecrawl.crawl()` instead of `firecrawl.crawl_url()`. -
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.fixUpdate your import statement and class instantiation: `from firecrawl import Firecrawl` and `firecrawl = Firecrawl(api_key="...")`. -
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.fixObtain 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")`.
Warnings
- breaking FirecrawlApp class renamed to Firecrawl in v2.0. from firecrawl import FirecrawlApp raises ImportError. All v1 tutorial code is broken.
- breaking Method names changed in v2: scrape_url() → scrape(), crawl_url() → crawl(), check_crawl_status() → get_crawl_status(). All old method calls raise AttributeError.
- 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.
- gotcha pip install firecrawl installs a DIFFERENT package — not the official Firecrawl SDK. The correct install is pip install firecrawl-py.
- 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.
- 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.
- 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`.
Install
-
pip install firecrawl-py -
pip install firecrawl
Imports
- Firecrawl
# Old v1 API — FirecrawlApp class and scrape_url/crawl_url methods removed: from firecrawl import FirecrawlApp # ImportError in v2+ app = FirecrawlApp(api_key='fc-YOUR_API_KEY') result = app.scrape_url('https://example.com') # method removed crawl = app.crawl_url('https://example.com', params={...}) # removedfrom firecrawl import Firecrawl from firecrawl.types import ScrapeOptions firecrawl = Firecrawl(api_key='fc-YOUR_API_KEY') # Scrape (v2+ method name) result = firecrawl.scrape( 'https://example.com', formats=['markdown', 'html'] ) print(result.markdown) # Crawl (v2+ method name) crawl = firecrawl.crawl( 'https://example.com', limit=100, scrape_options=ScrapeOptions(formats=['markdown']) )
Quickstart
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)