Firecrawl: Web Scraping API for AI and LLM Applications
Firecrawl is a managed web scraping API designed specifically for AI and LLM needs. Unlike traditional web scrapers, Firecrawl produces output in clean, structured markdown format, ready for use in RAG (Retrieval-Augmented Generation) pipelines, fine-tuning datasets, or knowledge base construction.
This article covers how to use Firecrawl for various web scraping scenarios in the context of AI applications, from single page scraping to building a complete knowledge base ingestion pipeline.
Why Firecrawl?
Web scraping for AI purposes has unique challenges. Traditional scraping tools like BeautifulSoup or Scrapy produce raw HTML that needs manual cleaning. Modern pages often use JavaScript rendering that requires browser automation. Firecrawl solves these problems:
- Clean markdown output: Content directly in a format that LLMs understand
- JavaScript rendering: Handles SPA and dynamic content automatically
- Structured data extraction: Extract structured data using built-in LLM
- Website crawling: Automatically explore entire websites by following links
- Managed infrastructure: No need to manage proxies, browsers, or servers
- Automatic rate limiting: Respects robots.txt and rate limits
Installation and Setup
SDK Installation
pip install firecrawl-py
API Key Setup
Register at firecrawl.dev to get an API key:
from firecrawl import FirecrawlApp
app = FirecrawlApp(apikey="fc-YOURAPIKEYHERE")
Or set it as an environment variable:
export FIRECRAWLAPIKEY="fc-YOURAPIKEYHERE"
import os
from firecrawl import FirecrawlApp
app = FirecrawlApp(apikey=os.getenv("FIRECRAWLAPIKEY"))
Scraping a Single Page
Markdown Output
Firecrawl converts web pages into clean markdown:
from firecrawl import FirecrawlApp
app = FirecrawlApp(apikey="fc-YOURAPIKEY")
Scrape a single page
result = app.scrapeurl(
"https://docs.python.org/3/tutorial/classes.html",
params={"formats": ["markdown"]}
)
Access markdown content
markdowncontent = result.get("markdown", "")
print(f"Content length: {len(markdowncontent)} characters")
print(markdowncontent[:500])
Page metadata
metadata = result.get("metadata", {})
print(f"Title: {metadata.get('title')}")
print(f"Description: {metadata.get('description')}")
print(f"Language: {metadata.get('language')}")
HTML Output
If you need raw HTML:
result = app.scrapeurl(
"https://example.com/article",
params={"formats": ["html", "markdown"]}
)
htmlcontent = result.get("html", "")
markdowncontent = result.get("markdown", "")
print(f"HTML length: {len(htmlcontent)}")
print(f"Markdown length: {len(markdowncontent)}")
Screenshot
Firecrawl can also capture page screenshots:
result = app.scrapeurl(
"https://example.com",
params={"formats": ["screenshot"]}
)
screenshot
url = result.get("screenshot")
print(f"Screenshot URL: {screenshoturl}")
Download screenshot
import requests
if screenshoturl:
response = requests.get(screenshoturl)
with open("screenshot.png", "wb") as f:
f.write(response.content)
print("Screenshot saved!")
Crawling an Entire Website
Firecrawl can explore an entire website by automatically following links:
from firecrawl import FirecrawlApp
app = FirecrawlApp(apikey="fc-YOURAPIKEY")
Crawl website with configuration
crawlresult = app.crawlurl(
"https://docs.python.org/3/tutorial/",
params={
"limit": 50, # Maximum 50 pages
"maxDepth": 3, # Maximum link depth
"includePaths": ["/3/tutorial/"], # Only specific paths
"excludePaths": ["/3/tutorial/index.html"],
"scrapeOptions": {
"formats": ["markdown"]
}
},
pollinterval=5 # Check status every 5 seconds
)
Process results
pages = crawlresult.get("data", [])
print(f"Total pages crawled: {len(pages)}")
for page in pages:
metadata = page.get("metadata", {})
markdown = page.get("markdown", "")
url = metadata.get("sourceURL", "unknown")
print(f" - {url}: {len(markdown)} chars")
Asynchronous Crawling
For large websites, use asynchronous crawling:
from firecrawl import FirecrawlApp
import time
app = FirecrawlApp(apikey="fc-YOURAPIKEY")
Start async crawl
crawlstatus = app.asynccrawlurl(
"https://docs.langchain.com/",
params={
"limit": 100,
"maxDepth": 3,
"scrapeOptions": {
"formats": ["markdown"]
}
}
)
crawlid = crawlstatus.get("id")
print(f"Crawl started with ID: {crawlid}")
Poll for status
while True:
status = app.checkcrawlstatus(crawlid)
state = status.get("status")
completed = status.get("completed", 0)
total = status.get("total", 0)
print(f"Status: {state} - {completed}/{total} pages")
if state == "completed":
pages = status.get("data", [])
print(f"Crawl complete! Total: {len(pages)} pages")
break
time.sleep(10)
Map URLs
Firecrawl provides a map feature to get a list of all URLs in a website without crawling all content:
from firecrawl import FirecrawlApp
app = FirecrawlApp(apikey="fc-YOURAPIKEY")
Map all URLs
mapresult = app.mapurl(
"https://docs.python.org/3/",
params={"limit": 500}
)
urls = mapresult.get("links", [])
print(f"Total URLs found: {len(urls)}")
Filter relevant URLs
tutorialurls = [url for url in urls if "/tutorial/" in url]
print(f"Tutorial URLs: {len(tutorialurls)}")
for url in tutorialurls[:10]:
print(f" - {url}")
Structured Data Extraction with LLM
Firecrawl can extract structured data from web pages using a built-in LLM and a schema you define:
from firecrawl import FirecrawlApp
app = FirecrawlApp(apikey="fc-YOURAPIKEY")
Define extraction schema
schema = {
"type": "object",
"properties": {
"title": {"type": "string", "description": "Article title"},
"author": {"type": "string", "description": "Author name"},
"publisheddate": {"type": "string", "description": "Publication date"},
"summary": {"type": "string", "description": "Article summary in 2-3 sentences"},
"topics": {
"type": "array",
"items": {"type": "string"},
"description": "Main topics discussed"
},
"codelanguages": {
"type": "array",
"items": {"type": "string"},
"description": "Programming languages used in code examples"
}
},
"required": ["title", "summary", "topics"]
}
result = app.scrapeurl(
"https://blog.example.com/machine-learning-tutorial",
params={
"formats": ["extract"],
"extract": {
"schema": schema,
"prompt": "Extract the key information from this technical blog post."
}
}
)
extracted = result.get("extract", {})
print(f"Title: {extracted.get('title')}")
print(f"Author: {extracted.get('author')}")
print(f"Summary: {extracted.get('summary')}")
print(f"Topics: {', '.join(extracted.get('topics', []))}")
Product Data Extraction
productschema = {
"type": "object",
"properties": {
"productname": {"type": "string"},
"price": {"type": "number"},
"currency": {"type": "string"},
"rating": {"type": "number"},
"reviewcount": {"type": "integer"},
"features": {
"type": "array",
"items": {"type": "string"}
},
"availability": {"type": "string"}
}
}
result = app.scrapeurl(
"https://shop.example.com/product/gpu-rtx4090",
params={
"formats": ["extract"],
"extract": {
"schema": productschema,
"prompt": "Extract product information including price, rating, and features."
}
}
)
product = result.get("extract", {})
print(f"Product: {product.get('productname')}")
print(f"Price: {product.get('currency', '