DS DevShelfHub Projects · AI tools
Tutorials / Firecrawl / RAG Integration
Firecrawl RAG · 9 min read Page 7 of 10

Integrating with RAG Pipelines

Use Firecrawl as your document ingestion layer. Build a complete RAG pipeline: crawl → chunk → embed → store → retrieve.

By DevShelfHub

Series progress 7 / 10
Firecrawl RAG integration tutorial — Integrating with RAG Pipelines

Why Firecrawl is perfect for RAG

RAG (Retrieval Augmented Generation) pipelines need clean, structured content to work well. Firecrawl solves the hardest part: extracting readable content from messy web pages.

Raw HTML (bad for RAG)

Boilerplate, ads, navigation, tracking scripts all mixed with content. Your embedding model wastes tokens on noise.

Firecrawl Markdown (perfect for RAG)

Clean, readable text. Headings structure the content. Links are preserved. No ads or boilerplate. Perfect for embedding.

The RAG pipeline with Firecrawl

Here's the complete flow:

1. Crawl: Use Firecrawl to crawl a site and extract Markdown from each page.

2. Chunk: Split the Markdown by headings or token count into manageable pieces.

3. Embed: Generate embeddings for each chunk using an embedding model (OpenAI, Hugging Face, etc).

4. Store: Save chunks and embeddings in a vector database (FAISS, Pinecone, Weaviate, etc).

5. Retrieve & Generate: When a user asks a question, retrieve similar chunks from the vector DB and pass them to an LLM.

Full working example

Here's a complete RAG pipeline using Firecrawl, OpenAI embeddings, and FAISS.

python
import os
from firecrawl import FirecrawlApp
from openai import OpenAI
import faiss, numpy as np

firecrawl = FirecrawlApp(api_key=os.environ["FIRECRAWL_API_KEY"])
openai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

# Step 1: Crawl the docs
crawl = firecrawl.crawl_url(
    "https://docs.example.com",
    params={"limit": 100, "scrapeOptions": {"formats": ["markdown"], "onlyMainContent": True}}
)

# Step 2: Chunk each page by heading
def chunk_by_heading(markdown: str) -> list[str]:
    sections = markdown.split("\n## ")
    return [s.strip() for s in sections if len(s.strip()) > 50]

chunks = []
for page in crawl["data"]:
    chunks.extend(chunk_by_heading(page.get("markdown", "")))

# Step 3: Embed
def embed(texts: list[str]) -> np.ndarray:
    res = openai_client.embeddings.create(input=texts, model="text-embedding-3-small")
    return np.array([r.embedding for r in res.data], dtype="float32")

embeddings = embed(chunks)

# Step 4: Store in FAISS
index = faiss.IndexFlatL2(embeddings.shape[1])
index.add(embeddings)

# Step 5: Query
def search(query: str, k: int = 3) -> list[str]:
    q_emb = embed([query])
    _, ids = index.search(q_emb, k)
    return [chunks[i] for i in ids[0]]

results = search("How do I authenticate?")
for r in results:
    print(r[:300])
    print("---")

Chunking strategies

Firecrawl gives you Markdown. You need to split it into chunks for embedding.

By heading (recommended)

Split on ## markers. Firecrawl's Markdown headings make natural chunk boundaries.

By token count

Use a library like tiktoken to keep chunks under a token limit (e.g., 512 tokens).

By paragraph

Split on newlines. Simple but less coherent than heading-based chunking.

Preprocessing crawled content

Sometimes you need to clean up Firecrawl's output before storing in your vector DB.

Strip repeated sections: Navigation, footers, and sidebars might appear on every page. Remove them.

Remove tracking info: Analytics pixels, UTM parameters in links. Clean them up.

Normalize whitespace: Multiple newlines → single newline.

Remove metadata comments: Firecrawl might include HTML comments. Strip them.

Add source tracking: Keep the original URL with each chunk for attribution.

Incremental updates

Don't re-crawl everything every day. Track changes and update only what's new.

# Strategy: hash-based change detection
import hashlib
from datetime import datetime

last_crawl = load_from_db("last_crawl_metadata")

for page in pages:
    content_hash = hashlib.sha256(page["markdown"].encode()).hexdigest()
    if content_hash != last_crawl.get(page["url"]):
        # Content changed — re-chunk, re-embed, update vectors
        update_vector_db(page)
        save_metadata(page["url"], content_hash, datetime.now())

Summary

  • Firecrawl → clean Markdown input for RAG pipelines
  • Chunk by headings for coherent retrieval
  • Embed with OpenAI, Cohere, or local models
  • Store in FAISS, Pinecone, or Weaviate
  • Use incremental updates to save costs

Building production RAG with Firecrawl

The scrape-chunk-embed-store pipeline is the foundation of every production RAG system. Firecrawl handles the hardest part — extracting clean, structured text from messy web pages — so you can focus on chunking strategy, embedding model selection, and retrieval tuning. The quality of your scraping directly determines retrieval accuracy: garbage in, garbage out.

For best results, use Firecrawl's Markdown output and chunk by heading structure rather than fixed token counts. Headings provide natural semantic boundaries that preserve context within each chunk. Combine this with metadata extraction (page title, section heading, URL) stored alongside each chunk so your retrieval pipeline can filter by source. If your RAG system still produces low-quality answers after optimizing retrieval, consider fine-tuning the generation model for your specific domain — the combination of RAG for fresh knowledge and fine-tuning for domain behavior produces the best results in practice.

Firecrawl RAG FAQ

How do I use Firecrawl in a RAG pipeline?

Crawl your target site with Firecrawl, split the Markdown output into chunks, generate embeddings with an embedding model, store them in a vector database, and query at inference time.

What chunking strategy works best with Firecrawl output?

Use recursive character splitting on the Markdown output with a chunk size of 500-1000 tokens and 100-200 token overlap. Firecrawl's clean Markdown preserves document structure for coherent chunks.

Which vector database should I use?

For getting started, use Chroma or FAISS locally. For production, consider Pinecone, Weaviate, or Qdrant. The choice depends on scale, hosting preferences, and filtering requirements.

Can I keep my RAG data fresh with Firecrawl?

Yes. Schedule periodic crawls to re-index changed pages. Firecrawl can detect content changes between runs, so you only re-embed pages that actually updated.

How does Firecrawl compare to LangChain document loaders?

LangChain's WebBaseLoader uses basic HTTP requests and struggles with JavaScript pages. Firecrawl handles SPAs, manages retries, and outputs cleaner Markdown as a more robust ingestion layer.

Continue learning with our RAG pipeline tutorial series and real-world use cases.