Metadata-Version: 2.4
Name: firecrawl
Version: 4.53.2
Summary: Python SDK for Firecrawl, the context API for AI agents: search, scrape, parse, crawl, map, and interact with the web, run Agent and Monitor jobs, and search scientific papers (PubMed, bioRxiv, medRxiv, arXiv)
Home-page: https://github.com/firecrawl/firecrawl
Author: Firecrawl
Author-email: Firecrawl <nick@mendable.ai>
Maintainer-email: Firecrawl <nick@mendable.ai>
License: MIT License
Project-URL: Documentation, https://docs.firecrawl.dev
Project-URL: Source, https://github.com/firecrawl/firecrawl
Project-URL: Tracker, https://github.com/firecrawl/firecrawl/issues
Keywords: SDK,API,firecrawl,web scraping,crawler,web search,literature search,research,scientific papers,academic search,biomedical,life sciences,pubmed,biorxiv,medrxiv,arxiv,preprints,citations,bioinformatics
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Topic :: Internet
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing
Classifier: Topic :: Text Processing :: Indexing
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests
Requires-Dist: httpx
Requires-Dist: python-dotenv
Requires-Dist: websockets
Requires-Dist: nest-asyncio
Requires-Dist: pydantic>=2.0
Requires-Dist: aiohttp
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# Firecrawl Python SDK

The Firecrawl Python SDK is the Python client for Firecrawl, the context API for AI agents. Search, scrape, parse, crawl, map, and interact with the web, run Agent and Monitor jobs, and get back clean Markdown or structured data your agents can ship with.

## Installation

To install the Firecrawl Python SDK, you can use pip:

```bash 
pip install firecrawl
```

## Usage

1. Get an API key from [firecrawl.dev](https://firecrawl.dev)
2. Set the API key as an environment variable named `FIRECRAWL_API_KEY` or pass it as a parameter to the `Firecrawl` class.

Here's an example of how to use the SDK:

```python 
from firecrawl import Firecrawl
from firecrawl.types import ScrapeOptions

firecrawl = Firecrawl(api_key="fc-YOUR_API_KEY")

# Scrape a website (v2):
data = firecrawl.scrape(
  'https://firecrawl.dev', 
  formats=['markdown', 'html']
)
print(data)

# Crawl a website (v2 waiter):
crawl_status = firecrawl.crawl(
  'https://firecrawl.dev', 
  limit=100, 
  scrape_options=ScrapeOptions(formats=['markdown', 'html'])
)
print(crawl_status)
```

### Request origin

Requests carry an `origin` tag that identifies the client. Pass the `origin` argument to set the client default. Per-call overrides are available on methods that explicitly accept an `origin` argument, such as `interact`.

```python
firecrawl = Firecrawl(api_key="fc-YOUR_API_KEY", origin="python-sdk.my-wrapper@1.0.0")
```

By default the tag is `python-sdk@<version>`. When the client is created by code inside an installed package (a wrapper library), the default is `python-sdk.<package>@<version>` instead, for example `python-sdk.some-agent@<version>`. Application code, REPLs and notebooks keep the plain default. Detection runs once when the client is created and sends only the installed distribution name, lowercased and sanitized into a slug. Set `FIRECRAWL_DISABLE_CALLER_ORIGIN=1` to always use the plain default.

### Scraping a URL

To scrape a single URL, use the `scrape` method. It takes the URL as a parameter and returns a document with the requested formats.

```python 
# Scrape a website (v2):
scrape_result = firecrawl.scrape('https://firecrawl.dev', formats=['markdown', 'html'])
print(scrape_result)
```

### Video extraction

Use the `video` format on supported video URLs, including YouTube and TikTok. The returned `video` field is a signed URL to the extracted video file.

```python
doc = firecrawl.scrape('https://www.youtube.com/watch?v=dQw4w9WgXcQ', formats=['video'])
print(doc.video)
```

### Product extraction

Use the `product` format on product pages to deterministically pull structured product data (title, price, availability, variants). It is the deterministic counterpart to the LLM-based `json` format.

```python
doc = firecrawl.scrape('https://firecrawl.dev', formats=['product'])
print(doc.product)
```

### Menu extraction

Use the `menu` format on menu pages to deterministically pull structured menu data (merchant, sections, items, prices, availability). It is the deterministic counterpart to the LLM-based `json` format.

```python
doc = firecrawl.scrape('https://example.com/restaurant/menu', formats=['menu'])
print(doc.menu)
```

### Parsing uploaded files

Use `parse` to upload local bytes/files (`html`, `pdf`, `docx`, etc.) as multipart form data and return the parsed document.
`parse` does not support change tracking or browser-only options (actions, wait_for, location, mobile, screenshot, branding, audio, video).

```python
from firecrawl import Firecrawl
from firecrawl.v2.types import ParseOptions

firecrawl = Firecrawl(api_key="fc-YOUR_API_KEY")

doc = firecrawl.parse(
  b"<!DOCTYPE html><html><body><h1>Python Parse</h1></body></html>",
  filename="upload.html",
  content_type="text/html",
  options=ParseOptions(formats=["markdown"]),
)

print(doc.markdown)
```

To see which file formats `parse` accepts, call `get_parse_formats` (also available on `AsyncFirecrawl`). Each entry has `format`, `kind` (`"document"` or `"image"`), `extensions`, `mime_types`, and `available`, which is `False` when a format is disabled on the deployment.

```python
for f in firecrawl.get_parse_formats():
  print(f.format, f.kind, f.extensions, f.mime_types, f.available)
```

### Crawling a Website

To crawl a website, use the `crawl` method. It takes the starting URL and optional parameters as arguments. You can control depth, limits, formats, and more.

```python 
crawl_status = firecrawl.crawl(
  'https://firecrawl.dev', 
  limit=100, 
  scrape_options=ScrapeOptions(formats=['markdown', 'html']),
  poll_interval=30
)
print(crawl_status)
```

The result is a `CrawlJob`. It includes the job `id` and any `warning` from the API, so you can use the job after the crawl ends, for example with `get_crawl_errors(crawl_status.id)`. If the crawl does not finish within `timeout`, the SDK raises `CrawlJobTimeoutError`. It is a `TimeoutError` subclass with a `job_id` attribute, so you can check or cancel the job later.

```python
from firecrawl import CrawlJobTimeoutError

try:
  crawl_status = firecrawl.crawl('https://firecrawl.dev', limit=100, timeout=120)
except CrawlJobTimeoutError as e:
  firecrawl.cancel_crawl(e.job_id)
```

With `AsyncFirecrawl`, you can stop waiting for `crawl()` with `Task.cancel()`, `asyncio.timeout` or `asyncio.wait_for`. If the crawl already has a job id, the SDK then sends a best-effort cancel for it. If the cancellation comes before `start_crawl` returns the id, the SDK sends no cancel, and the crawl can keep running. After the cancel, `Task.cancel()` gives you `asyncio.CancelledError`. `asyncio.timeout` and `asyncio.wait_for` give you `TimeoutError`. To keep the crawl running after you stop waiting, use `start_crawl` and `wait_crawl`.

### Asynchronous Crawling

<Tip>Looking for async operations? Check out the [Async Class](#async-class) section below.</Tip>

To enqueue a crawl asynchronously, use `start_crawl`. It returns the crawl `ID` which you can use to check the status of the crawl job.

```python 
crawl_job = firecrawl.start_crawl(
  'https://firecrawl.dev', 
  limit=100, 
  scrape_options=ScrapeOptions(formats=['markdown', 'html']),
)
print(crawl_job)
```

### Checking Crawl Status

To check the status of a crawl job, use the `get_crawl_status` method. It takes the job ID as a parameter and returns the current status of the crawl job.

```python 
crawl_status = firecrawl.get_crawl_status("<crawl_id>")
print(crawl_status)
```

### Manual Pagination (v2)

Crawl and batch scrape status responses may include a `next` URL when more data is available. The SDK auto-paginates by default; to page manually, disable auto-pagination and pass the opaque `next` URL back to the SDK.

```python
from firecrawl.v2.types import PaginationConfig

# Crawl: fetch one page at a time
crawl_job = firecrawl.start_crawl("https://firecrawl.dev", limit=100)
status = firecrawl.get_crawl_status(
  crawl_job.id,
  pagination_config=PaginationConfig(auto_paginate=False),
)
if status.next:
  page2 = firecrawl.get_crawl_status_page(status.next)

# Batch scrape: fetch one page at a time
batch_job = firecrawl.start_batch_scrape(["https://firecrawl.dev"])
status = firecrawl.get_batch_scrape_status(
  batch_job.id,
  pagination_config=PaginationConfig(auto_paginate=False),
)
if status.next:
  page2 = firecrawl.get_batch_scrape_status_page(status.next)
```

### Cancelling a Crawl

To cancel an asynchronous crawl job, use the `cancel_crawl` method. It takes the job ID of the asynchronous crawl as a parameter and returns the cancellation status. It returns `False` if the crawl already completed.

```python 
cancel_crawl = firecrawl.cancel_crawl(id)
print(cancel_crawl)
```

### Map a Website

Use `map` to generate a list of URLs from a website. Options let you customize the mapping process, including whether to use the sitemap or include subdomains.

```python 
# Map a website (v2):
map_result = firecrawl.map('https://firecrawl.dev')
print(map_result)
```

### Search

Use `search` to search the web and optionally scrape the results in the same call.

```python
# Search the web (v2):
results = firecrawl.search("what is retrieval augmented generation?", limit=5)
for result in results.web or []:
    print(result.url, "-", result.title)

# Scrape every result as part of the search:
results = firecrawl.search(
    "firecrawl changelog",
    limit=3,
    scrape_options={"formats": ["markdown"]},
)
```

Results are grouped by source: `.web`, `.news`, `.images` and `.developer`.

Use `categories` to narrow web search to a kind of site:

```python
results = firecrawl.search("nanopore basecalling accuracy", categories=["research"])
```

> **`categories=["research"]` is a website filter, not the paper index.** It
> restricts ordinary web search to roughly 14 academic domains (arxiv.org,
> pubmed.ncbi.nlm.nih.gov, nature.com, biorxiv.org, ...) and returns web page
> results. To search papers themselves, use `search_papers` below.

### Developer search

Use `developer_search` for the dedicated developer index and its complete
filter and response contract. Generic `search(categories=["developer"])`
returns only the first passage as a description and does not accept these
filters.

```python
evidence = firecrawl.developer_search(
    "configure retry backoff",
    repos=["firecrawl/firecrawl"],
    types=["issue", "pull_request", "readme"],
    passages=3,
    language="TypeScript",
    license="MIT",
)

for result in evidence.results:
    # Result kind is the id prefix; the API intentionally omits a type field.
    print(result.id, result.license)
    for passage in result.passages:
        print(passage.text, passage.citation_url)
print(evidence.repos)  # indexed-status echoes for requested repos
```

`developer_search` also supports `sources`, `topic`, `min_stars`, `max_stars`,
`archived`, `fork`, and `skills="only"`. Supplying both `repos` and `sources`
OR-combines GitHub-backed and documentation results.

### Government search

Use `gov_search` to search the Firecrawl Government Index: primary
law and regulatory material from US federal, state, and local government
sources, including statutes, regulations, codes, court opinions, and other
government publications. Results come back in the ordinary web-result shape.
Generic `search("food labeling requirements", categories=["gov"])` returns
index results inside `.web`; like `developer`, it cannot be combined with other
categories.

```python
law = firecrawl.gov_search("food labeling requirements", k=5)

for result in law.data.web:
    print(result.position, result.title, result.url)
```

### Research / paper search

Use `search_papers` to search Firecrawl's research paper index: ~43M paper
abstracts, roughly 90% biomedical and life sciences (PubMed, bioRxiv, medRxiv),
plus arXiv for physics, mathematics and computer science.

```python
# Search the paper index (semantic search over abstracts):
papers = firecrawl.search_papers(
    "CRISPR base editing off-target effects in primary human T cells",
    k=10,
)
for paper in papers["results"]:
    print(paper["primaryId"], "-", paper["title"])

# Inspect one paper's metadata (accepts pmid:, pmcid:, doi: or arxiv: ids):
paper = firecrawl.inspect_paper("pmid:<id>")

# Read the passages inside a paper that answer a specific question:
passages = firecrawl.read_paper(
    "pmid:<id>",
    "what was the primary endpoint and the reported hazard ratio?",
    k=4,
)

# Expand along the citation graph, re-ranked for your stated intent:
related = firecrawl.related_papers(
    "pmid:<id>",
    intent="replication attempts in larger cohorts",
    k=20,
)
```

> **`search_github` is deprecated.** The research index GitHub endpoint stops
> responding after 2026-11-03. Use `developer_search` instead: it searches
> GitHub issues, pull requests and readmes plus curated documentation sources,
> returns matched passages, and adds filters for repo, language, license and
> stars. It does not carry over the `scores` breakdown or the
> `resultType: "web"` fallback results. See
> [the developer index docs](https://docs.firecrawl.dev/features/developer).

> **Response keys are camelCase.** Unlike the rest of the SDK, the research
> methods return the raw JSON body as a `dict` — they are not parsed into typed
> models and not normalized to snake_case. Expect `paperId`, `primaryId`,
> `createdDate`, `articleRank`, `poolSize`, and so on.

Every method above is also available on `AsyncFirecrawl` with the same name.

### Scrape-bound interactive browsing (v2)

Use a scrape job ID to keep interacting with the replayed browser context:

```python
doc = firecrawl.scrape(
  "https://example.com",
  actions=[{"type": "click", "selector": "a[href='/pricing']"}],
)

scrape_job_id = doc.metadata_typed.scrape_id
if not scrape_job_id:
  raise RuntimeError("Missing scrape job id")

run = firecrawl.interact(
  scrape_job_id,
  code="print(await page.url())",
  language="python",
  timeout=60,
)
print(run.stdout)

firecrawl.stop_interaction(scrape_job_id)
```

{/* ### Extracting Structured Data from Websites

  To extract structured data from websites, use the `extract` method. It takes the URLs to extract data from, a prompt, and a schema as arguments. The schema is a Pydantic model that defines the structure of the extracted data.

  <ExtractPythonShort /> */}

### Crawling a Website with WebSockets

To crawl a website with WebSockets, use the `crawl_url_and_watch` method. It takes the starting URL and optional parameters as arguments. The `params` argument allows you to specify additional options for the crawl job, such as the maximum number of pages to crawl, allowed domains, and the output format.

```python 
# inside an async function...
nest_asyncio.apply()

# Define event handlers
def on_document(detail):
    print("DOC", detail)

def on_error(detail):
    print("ERR", detail['error'])

def on_done(detail):
    print("DONE", detail['status'])

    # Function to start the crawl and watch process
async def start_crawl_and_watch():
    # Initiate the crawl job and get the watcher
    watcher = app.crawl_url_and_watch('firecrawl.dev', exclude_paths=['blog/*'], limit=5)

    # Add event listeners
    watcher.add_event_listener("document", on_document)
    watcher.add_event_listener("error", on_error)
    watcher.add_event_listener("done", on_done)

    # Start the watcher
    await watcher.connect()

# Run the event loop
await start_crawl_and_watch()
```

## Error Handling

The SDK handles errors returned by the Firecrawl API and raises appropriate exceptions. If an error occurs during a request, an exception will be raised with a descriptive error message.

## Async Class

For async operations, you can use the `AsyncFirecrawl` class. Its methods mirror the `Firecrawl` class, but you `await` them.

```python 
from firecrawl import AsyncFirecrawl

firecrawl = AsyncFirecrawl(api_key="YOUR_API_KEY")

# Async Scrape (v2)
async def example_scrape():
  scrape_result = await firecrawl.scrape(url="https://example.com")
  print(scrape_result)

# Async Parse (v2)
async def example_parse():
  parse_result = await firecrawl.parse(
    b"<!DOCTYPE html><html><body><h1>Async Parse</h1></body></html>",
    filename="upload.html",
    content_type="text/html",
  )
  print(parse_result)

# Async Crawl (v2)
async def example_crawl():
  crawl_result = await firecrawl.crawl(url="https://example.com")
  print(crawl_result)
```

## v1 compatibility

For legacy code paths, v1 remains available under `firecrawl.v1` with the original method names.

```python
from firecrawl import Firecrawl

firecrawl = Firecrawl(api_key="YOUR_API_KEY")

# v1 methods (feature‑frozen)
doc_v1 = firecrawl.v1.scrape_url('https://firecrawl.dev', formats=['markdown', 'html'])
crawl_v1 = firecrawl.v1.crawl_url('https://firecrawl.dev', limit=100)
map_v1 = firecrawl.v1.map_url('https://firecrawl.dev')
```

### Alexandria

With a matching API deployment, `search()` returns complete contracts in `tools`.
`domain_tools=True` adds domain matches to that same list. Find Tools provides free,
progressive catalogue lookup; Search always requires a query.

```python
result = firecrawl.search("podcast conversations about AI agents",
                         sources=["web", "alexandria"], domain_tools=True, limit=2)
print(result.tools[0].options)

catalogue = firecrawl.find_tools(providers=["particle"], limit=2)
if catalogue.items and catalogue.items[0].get("next"):
    details = firecrawl.scrape(alexandria=catalogue.items[0]["next"])
    for item in details.alexandria:
        if item.error:
            print(f"Lookup failed: {item.error.message}")
        else:
            print(item.data)
```

Use `scrape(alexandria={"provider": ..., "capability": ..., "options": ...})` to
execute a selected tool, or pass a list of up to ten calls. Check each item's
`error` before using `data`. Results and execution exceptions expose `request_id`;
reuse it with the identical payload when retrying. Automatic retries retain it.
The same methods are available with `await` on `AsyncFirecrawl`.
