Skip to main content

Firecrawl Python SDK: Complete Developer Guide 2026

· 3 min read
Yassine El Haddad
Software Developer & Automation Specialist

I build production AI agents, web scrapers, and automation pipelines. Most of what I publish here comes from the actual problems they run into: proxies that get banned, anti-bot stacks that fingerprint your client, RAG that drifts when the underlying data moves. Stack: Python, TypeScript, Go, FastAPI, LangChain, Crawlee, Playwright, deployed on AWS, GCP, and Cloudflare.

The Firecrawl Python SDK (firecrawl-py) provides a simple interface: scrape(), crawl(), and map_url(). Install with pip install firecrawl-py, initialize with your API key, and start scraping. The SDK returns snake_case by default and supports async via FirecrawlAsync.

Get started with Firecrawl →

Install and Authenticate

pip install firecrawl-py
from firecrawl import Firecrawl

app = Firecrawl(api_key="fc-YOUR-API-KEY")
# Or: app = Firecrawl() # reads FIRECRAWL_API_KEY from env

Store keys in environment variables. Never hardcode in source control.

Single-Page Scrape

doc = app.scrape("https://example.com/docs", formats=["markdown", "links"])
print(doc.get("markdown", "")[:300])
print(doc.get("links", [])[:5])

Formats: markdown, html, links, images, screenshots, extract. Use only_main_content=True (default) to exclude nav and footer.

Structured Extraction with Schema

Use the extract format with a JSON schema for structured output:

from pydantic import BaseModel

class CompanyProfile(BaseModel):
name: str
industry: str | None = None
headquarters: str | None = None
website: str

doc = app.scrape(
"https://example.com/about",
formats=["extract"],
extract={"schema": CompanyProfile.model_json_schema()}
)
print(doc.get("extract"))

Validate extracted fields before writing to storage.

Map URL Discovery

Discover URLs on a domain before crawling:

mapped = app.map_url("https://example.com", limit=5000, search="docs")
links = mapped.get("links", [])
docs_urls = [l["url"] for l in links if "/docs/" in l["url"]]
print(f"Found {len(docs_urls)} docs URLs")

map_url costs 1 credit per request regardless of link count (up to 100,000).

Crawl Workflow

Crawl is async. Start, then poll for completion:

job = app.crawl_url(
"https://example.com/docs",
limit=100,
scrape_options={"formats": ["markdown"]}
)
job_id = job.get("id")

# Poll until done
status = app.check_crawl_status(job_id)
while status.get("status") not in ("completed", "failed"):
time.sleep(5)
status = app.check_crawl_status(job_id)

if status.get("status") == "completed":
data = app.get_crawl_data(job_id)
for page in data.get("data", []):
print(page.get("markdown", "")[:200])

Use include_paths and exclude_paths to scope the crawl.

Async Variant

For concurrent requests, use the async client:

from firecrawl import FirecrawlAsync
import asyncio

async def main():
app = FirecrawlAsync(api_key="fc-YOUR-API-KEY")
tasks = [
app.scrape("https://example.com/page1"),
app.scrape("https://example.com/page2"),
]
results = await asyncio.gather(*tasks)
return results

asyncio.run(main())

Respect rate limits. Free tier: 2 concurrent; Hobby: 5; Standard: 50.

Error Handling

try:
doc = app.scrape(url)
if not doc:
raise ValueError("Empty response")
except Exception as e:
# Handle 429, 402, 500
if "rate limit" in str(e).lower():
time.sleep(60) # Backoff and retry

Add retries with exponential backoff. Keep source_url, run_id, and timestamp on every record for debugging.

Production Checklist

  • Use environment variables for API keys
  • Add retry logic with capped attempts
  • Log request ID, domain, endpoint
  • Validate response structure before downstream writes
  • Monitor cost per valid record, not just request success
Apify Affiliate Banner 728x90Apify Affiliate Banner 728x90Apify Affiliate Banner 300x50Apify Affiliate Banner 300x50
Next step

See the Firecrawl LangChain integration for RAG pipelines with document loaders.

Frequently Asked Questions

Run pip install firecrawl-py. Initialize with Firecrawl(api_key='...') or set FIRECRAWL_API_KEY in env.

Yes. Use formats=['extract'] with a JSON schema (e.g. from Pydantic) and validate outputs before production.

Yes. Use FirecrawlAsync for concurrent scraping. Respect plan limits: 2–50 concurrent depending on tier.

Track field completeness, failure rate by domain, retry volume, and cost per valid record.

Common mistakes and fixes

ModuleNotFoundError: No module named 'firecrawl'

Run pip install firecrawl-py. The package name is firecrawl-py, import as firecrawl.

API returns camelCase, I need snake_case

The SDK converts response fields to snake_case automatically.