{"id":229,"library":"firecrawl-py","title":"Firecrawl","description":"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.","status":"active","version":"4.21.0","language":"python","source_language":"en","source_url":"https://docs.firecrawl.dev/sdks/python","tags":["web-scraping","llm","markdown","crawling","ai","rag"],"install":[{"cmd":"pip install firecrawl-py","lang":"bash","label":"Official SDK (correct)"},{"cmd":"pip install firecrawl","lang":"bash","label":"Different package — NOT the official Firecrawl SDK"}],"dependencies":[{"reason":"Required. Installed automatically.","package":"requests","optional":false},{"reason":"Required. Installed automatically.","package":"pydantic","optional":false},{"reason":"Required for async support. Installed automatically.","package":"aiohttp","optional":false},{"reason":"Required for crawl watching. Installed automatically.","package":"websockets","optional":false}],"imports":[{"note":"Class renamed from FirecrawlApp to Firecrawl in v2. Methods renamed: scrape_url() → scrape(), crawl_url() → crawl(), check_crawl_status() → get_crawl_status(). Old v1 code raises ImportError or AttributeError on v2+.","wrong":"# Old v1 API — FirecrawlApp class and scrape_url/crawl_url methods removed:\nfrom firecrawl import FirecrawlApp  # ImportError in v2+\napp = FirecrawlApp(api_key='fc-YOUR_API_KEY')\nresult = app.scrape_url('https://example.com')  # method removed\ncrawl = app.crawl_url('https://example.com', params={...})  # removed","symbol":"Firecrawl","correct":"from firecrawl import Firecrawl\nfrom firecrawl.types import ScrapeOptions\n\nfirecrawl = Firecrawl(api_key='fc-YOUR_API_KEY')\n\n# Scrape (v2+ method name)\nresult = firecrawl.scrape(\n    'https://example.com',\n    formats=['markdown', 'html']\n)\nprint(result.markdown)\n\n# Crawl (v2+ method name)\ncrawl = firecrawl.crawl(\n    'https://example.com',\n    limit=100,\n    scrape_options=ScrapeOptions(formats=['markdown'])\n)"}],"quickstart":{"code":"from firecrawl import Firecrawl\nfrom firecrawl.types import ScrapeOptions\nimport os\n\n# API key from env or direct\nfirecrawl = Firecrawl(api_key=os.environ.get('FIRECRAWL_API_KEY'))\n\n# Scrape single URL → markdown\nresult = firecrawl.scrape(\n    'https://docs.firecrawl.dev',\n    formats=['markdown', 'html']\n)\nprint(result.markdown[:500])\nprint(result.metadata.title)\n\n# Crawl entire site (blocking, auto-polls)\ncrawl = firecrawl.crawl(\n    'https://docs.firecrawl.dev',\n    limit=50,\n    scrape_options=ScrapeOptions(formats=['markdown']),\n    poll_interval=5\n)\nfor doc in crawl.data:\n    print(doc.metadata.source_url, len(doc.markdown or ''))\n\n# Async crawl (non-blocking)\njob = firecrawl.start_crawl(\n    'https://docs.firecrawl.dev',\n    limit=50\n)\nstatus = firecrawl.get_crawl_status(job.id)","lang":"python","description":"v2+ API. scrape() for single URLs, crawl() blocks until done, start_crawl() for async."},"warnings":[{"fix":"Replace: from firecrawl import FirecrawlApp → from firecrawl import Firecrawl. Replace: FirecrawlApp(api_key=...) → Firecrawl(api_key=...)","message":"FirecrawlApp class renamed to Firecrawl in v2.0. from firecrawl import FirecrawlApp raises ImportError. All v1 tutorial code is broken.","severity":"breaking","affected_versions":">= 2.0"},{"fix":"Update all method calls: app.scrape_url(url) → firecrawl.scrape(url, formats=[...]), app.crawl_url(url, params) → firecrawl.crawl(url, ...)","message":"Method names changed in v2: scrape_url() → scrape(), crawl_url() → crawl(), check_crawl_status() → get_crawl_status(). All old method calls raise AttributeError.","severity":"breaking","affected_versions":">= 2.0"},{"fix":"Pin exact version in requirements.txt. Check GitHub releases before upgrading.","message":"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.","severity":"breaking","affected_versions":"all"},{"fix":"Always use pip install firecrawl-py. The import is still from firecrawl import Firecrawl.","message":"pip install firecrawl installs a DIFFERENT package — not the official Firecrawl SDK. The correct install is pip install firecrawl-py.","severity":"gotcha","affected_versions":"all"},{"fix":"Use SDK snake_case field names: result.metadata.source_url not result.metadata.sourceURL.","message":"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.","severity":"gotcha","affected_versions":">= 2.0"},{"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')`.","message":"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.","severity":"breaking","affected_versions":"all"},{"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')`.","message":"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`.","severity":"breaking","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T12:05:58.894Z","next_check":"2026-06-27T00:00:00.000Z","problems":[{"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.","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.","error":"ModuleNotFoundError: No module named 'firecrawl'"},{"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()`.","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.","error":"AttributeError: 'Firecrawl' object has no attribute 'scrape_url'"},{"fix":"Update your import statement and class instantiation: `from firecrawl import Firecrawl` and `firecrawl = Firecrawl(api_key=\"...\")`.","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.","error":"ImportError: cannot import name 'FirecrawlApp' from 'firecrawl'"},{"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\")`.","cause":"This HTTP status code indicates that the request could not be authenticated, typically due to a missing, incorrect, or expired API key.","error":"401 Unauthorized"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.74,"mem_mb":24.4,"disk_size":"106.6M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.76,"mem_mb":24.4,"disk_size":"46.3M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.24,"mem_mb":24.4,"disk_size":"178M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.24,"mem_mb":24.4,"disk_size":"48M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.33,"mem_mb":26.4,"disk_size":"117.0M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.31,"mem_mb":26.4,"disk_size":"51.1M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.97,"mem_mb":26.4,"disk_size":"189M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.95,"mem_mb":26.4,"disk_size":"53M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.3,"mem_mb":26.2,"disk_size":"107.6M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.25,"mem_mb":26.2,"disk_size":"42.4M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.21,"mem_mb":26.2,"disk_size":"180M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.19,"mem_mb":26.2,"disk_size":"44M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.1,"mem_mb":26.7,"disk_size":"104.1M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.08,"mem_mb":26.7,"disk_size":"42.1M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.12,"mem_mb":26.7,"disk_size":"178M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":2.04,"mem_mb":26.7,"disk_size":"44M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.64,"mem_mb":24.7,"disk_size":"106.4M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.65,"mem_mb":24.7,"disk_size":"46.2M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.48,"mem_mb":24.7,"disk_size":"179M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":1.52,"mem_mb":24.7,"disk_size":"48M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}