Skip to content

Rust SDK

Updated Feb 2026

A community-maintained Rust SDK for Firecrawl. Supports the v1 API with async methods powered by Tokio. Provides scraping, crawling, mapping, and JSON extraction capabilities.

Cratefirecrawl
Version^1.0
API Versionsv1
Maintained byCommunity
Sourcegithub.com/mendableai/firecrawl

Community SDK

This SDK is community-maintained and only supports the v1 API. For v2 features like search, batch scrape, extract, agent, and browser sessions, use the Python SDK or Node.js SDK.

Installation

Add the following to your Cargo.toml:

toml
[dependencies]
firecrawl = "^1.0"
tokio = { version = "^1", features = ["full"] }
serde_json = "1"

Initialization

Create a FirecrawlApp instance with your API key:

rust
use firecrawl::FirecrawlApp;

#[tokio::main]
async fn main() {
    let app = FirecrawlApp::new("fc-YOUR-API-KEY")
        .expect("Failed to initialize FirecrawlApp");
}

Methods

scrape_url()

Scrapes a single URL and returns a Document object. See Scrape feature docs for general parameter details.

Signature:

rust
async fn scrape_url(
    &self,
    url: &str,
    options: Option<ScrapeOptions>
) -> Result<Document, FirecrawlError>

ScrapeOptions fields:

FieldTypeDescription
formatsVec<ScrapeFormats>Output formats: Markdown, HTML, Json
json_optionsOption<ExtractOptions>JSON extraction schema and prompt

Basic example:

rust
use firecrawl::{FirecrawlApp, ScrapeOptions, ScrapeFormats};

#[tokio::main]
async fn main() {
    let app = FirecrawlApp::new("fc-YOUR-API-KEY").unwrap();

    let options = ScrapeOptions {
        formats: vec![ScrapeFormats::Markdown, ScrapeFormats::HTML],
        ..Default::default()
    };

    let result = app.scrape_url("https://firecrawl.dev", Some(options))
        .await
        .unwrap();

    println!("{}", result.markdown.unwrap_or_default());
}

With JSON extraction:

rust
use firecrawl::{FirecrawlApp, ScrapeOptions, ScrapeFormats, ExtractOptions};
use serde_json::json;

#[tokio::main]
async fn main() {
    let app = FirecrawlApp::new("fc-YOUR-API-KEY").unwrap();

    let options = ScrapeOptions {
        formats: vec![ScrapeFormats::Json],
        json_options: Some(ExtractOptions {
            schema: Some(json!({
                "type": "object",
                "properties": {
                    "title": { "type": "string" },
                    "description": { "type": "string" },
                    "features": {
                        "type": "array",
                        "items": { "type": "string" }
                    }
                },
                "required": ["title", "description"]
            })),
            prompt: Some("Extract the page title, description, and key features".to_string()),
            ..Default::default()
        }),
        ..Default::default()
    };

    let result = app.scrape_url("https://firecrawl.dev", Some(options))
        .await
        .unwrap();

    if let Some(extracted) = result.extract {
        println!("Extracted: {}", extracted);
    }
}

crawl_url()

Crawls a website synchronously, waiting for the job to complete before returning. See Crawl feature docs for general parameter details.

Signature:

rust
async fn crawl_url(
    &self,
    url: &str,
    options: Option<CrawlOptions>
) -> Result<CrawlResult, FirecrawlError>

CrawlOptions fields:

FieldTypeDescription
scrape_optionsOption<CrawlScrapeOptions>Scrape settings for each page
limitOption<u32>Maximum pages to crawl

Example:

rust
use firecrawl::{FirecrawlApp, CrawlOptions, CrawlScrapeOptions, CrawlScrapeFormats};

#[tokio::main]
async fn main() {
    let app = FirecrawlApp::new("fc-YOUR-API-KEY").unwrap();

    let options = CrawlOptions {
        scrape_options: Some(CrawlScrapeOptions {
            formats: Some(vec![CrawlScrapeFormats::Markdown]),
            ..Default::default()
        }),
        limit: Some(100),
        ..Default::default()
    };

    let result = app.crawl_url("https://docs.firecrawl.dev", Some(options))
        .await
        .unwrap();

    println!("Credits used: {}", result.credits_used);
    for doc in &result.data {
        println!("Page: {}", doc.markdown.as_deref().unwrap_or("N/A"));
    }
}

crawl_url_async()

Initiates a non-blocking crawl that returns immediately with a job ID.

Signature:

rust
async fn crawl_url_async(
    &self,
    url: &str,
    options: Option<CrawlOptions>
) -> Result<CrawlAsyncResponse, FirecrawlError>

Example:

rust
let response = app.crawl_url_async("https://docs.firecrawl.dev", Some(options))
    .await
    .unwrap();

println!("Crawl ID: {}", response.id);

check_crawl_status()

Checks the status of an asynchronous crawl job.

Signature:

rust
async fn check_crawl_status(
    &self,
    crawl_id: &str
) -> Result<CrawlStatus, FirecrawlError>

Parameters:

ParameterTypeRequiredDescription
crawl_id&strYesJob ID from crawl_url_async()

Example:

rust
use firecrawl::CrawlStatusTypes;

let status = app.check_crawl_status(&response.id)
    .await
    .unwrap();

if status.status == CrawlStatusTypes::Completed {
    println!("Crawl complete!");
    for doc in &status.data {
        println!("{}", doc.markdown.as_deref().unwrap_or("N/A"));
    }
} else {
    println!("Status: {:?}", status.status);
}

Polling loop:

rust
use tokio::time::{sleep, Duration};

loop {
    let status = app.check_crawl_status(&response.id).await.unwrap();

    match status.status {
        CrawlStatusTypes::Completed => {
            println!("Done! {} pages crawled", status.data.len());
            break;
        }
        CrawlStatusTypes::Failed => {
            eprintln!("Crawl failed");
            break;
        }
        _ => {
            println!("Still crawling...");
            sleep(Duration::from_secs(5)).await;
        }
    }
}

map_url()

Discovers all URLs on a website without scraping their content. See Map feature docs for general parameter details.

Signature:

rust
async fn map_url(
    &self,
    url: &str,
    options: Option<MapOptions>
) -> Result<Vec<String>, FirecrawlError>

Example:

rust
let urls = app.map_url("https://firecrawl.dev", None)
    .await
    .unwrap();

for url in &urls {
    println!("{}", url);
}
println!("Total URLs found: {}", urls.len());

Complete Example

A full working example demonstrating scrape, crawl, status check, and map:

rust
use firecrawl::{
    FirecrawlApp, ScrapeOptions, ScrapeFormats,
    CrawlOptions, CrawlScrapeOptions, CrawlScrapeFormats,
    CrawlStatusTypes,
};
use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let app = FirecrawlApp::new("fc-YOUR-API-KEY")?;

    // 1. Scrape a single page
    let scrape_opts = ScrapeOptions {
        formats: vec![ScrapeFormats::Markdown],
        ..Default::default()
    };
    let doc = app.scrape_url("https://firecrawl.dev", Some(scrape_opts)).await?;
    println!("Scraped: {} chars", doc.markdown.as_ref().map_or(0, |m| m.len()));

    // 2. Start an async crawl
    let crawl_opts = CrawlOptions {
        limit: Some(10),
        scrape_options: Some(CrawlScrapeOptions {
            formats: Some(vec![CrawlScrapeFormats::Markdown]),
            ..Default::default()
        }),
        ..Default::default()
    };
    let crawl = app.crawl_url_async("https://docs.firecrawl.dev", Some(crawl_opts)).await?;
    println!("Crawl started: {}", crawl.id);

    // 3. Poll for completion
    loop {
        let status = app.check_crawl_status(&crawl.id).await?;
        match status.status {
            CrawlStatusTypes::Completed => {
                println!("Crawl done: {} pages", status.data.len());
                break;
            }
            _ => {
                println!("Crawling...");
                sleep(Duration::from_secs(5)).await;
            }
        }
    }

    // 4. Map site URLs
    let urls = app.map_url("https://firecrawl.dev", None).await?;
    println!("Mapped {} URLs", urls.len());

    Ok(())
}

Error Handling

The SDK uses a FirecrawlError enum that implements the standard Error, Debug, and Display traits:

rust
match app.scrape_url("https://example.com", None).await {
    Ok(doc) => println!("Success: {}", doc.markdown.unwrap_or_default()),
    Err(e) => eprintln!("Firecrawl error: {}", e),
}

Common error scenarios:

ScenarioCause
Invalid API keyKey is missing, expired, or malformed
Rate limit exceededToo many requests in a short period
URL not reachableTarget URL is down or blocked
Network errorConnection timeout or DNS failure

Important Notes

  • All methods are async and require the Tokio runtime (#[tokio::main]).
  • Completed crawl results are auto-deleted after 24 hours. Download results promptly.
  • v2 API features (sitemap-only crawling, search, batch scrape, extract, agent, browser sessions) are not available in this SDK. For v2 sitemap-only crawling, you can call the REST endpoint directly using reqwest.

Limitations

Since this is a community SDK targeting v1, the following v2 features are not available:

  • Search
  • Batch scrape
  • Extract
  • Agent
  • Browser sessions
  • WebSocket watcher
  • Auto-pagination

For these features, use the Python SDK, Node.js SDK, or CLI.