★ Reading this for free? Get 20 structured AI courses + per-chapter AI tutor — the first chapter of every course free, no card.Start free in 30 seconds
Developer Guide

Crawl4AI Setup Guide: LLM-Ready Web Scraping for Local RAG (with Ollama)

August 23, 2026
14 min read
LocalAimaster Research Team

Want to go deeper than this article?

Free account unlocks the first chapter of all 25 courses — RAG, agents, MCP, voice AI, MLOps, real GitHub repos.

📚AI Learning Path

Ollama’s running. Here’s what to build with it. Go from “ollama run” to RAG apps, agents, and fine-tuned models — structured and hands-on. First chapter free.

Start free
Or own it for life — Lifetime $149, pay once

Short answer: pip install -U crawl4ai && crawl4ai-setup gets you Crawl4AI v0.9.2 (Apache-2.0, ~76.1k GitHub stars as of August 2026) — the best free tool for turning web pages into LLM-ready markdown. On our test machine it crawled a docs page to clean markdown in 6.4 seconds, its content filter cut 74% of the page's boilerplate, and the complete crawl → embed (Ollama) → store (ChromaDB) → query loop finished in under 8 seconds. No API key, no cloud, $0.

That last part is the whole reason this tool belongs on this site. Most "web scraping for RAG" tutorials end with an API bill. Crawl4AI is a Python library that runs on your machine, outputs markdown that drops straight into the local RAG pipeline we already built, and asks for nothing. This guide is the setup, a real crawl-to-answer demo with measured timings, and the honest list of where it falls short.


What Crawl4AI Is (and What It Is Not) {#what-is-crawl4ai}

Answer first: Crawl4AI is an open-source Python crawler whose output format is markdown instead of raw HTML — because markdown is what LLMs and RAG pipelines actually want. It drives a real headless browser, so JavaScript-rendered pages work, and its content filters strip navigation and boilerplate before the text ever reaches your embedder.

The pitch in one comparison. All figures are GitHub star counts and licenses as listed on each project's repo, checked August 2026:

ToolGitHub starsLicenseOutputRuns fully local?
Crawl4AI~76.1kApache-2.0LLM-ready markdown + structured JSON✅ Python library, no service required
Firecrawl~161.5kAGPL-3.0 core (MIT SDKs)LLM-ready markdown/JSON⚠️ Self-hostable, but built around the firecrawl.dev cloud API; cloud has extra features
Scrapy~63.7kBSD-3-ClauseRaw structured data (you clean it)✅ Fully local

Firecrawl is the bigger project and a genuinely good product — but its core is AGPL and its center of gravity is a hosted API. Scrapy is the veteran for industrial scraping, but it hands you raw extraction and leaves the LLM-prep layer to you. Crawl4AI sits exactly in our lane: permissive license, pip-installable, markdown out, nothing phones home.

What it is not: a point-and-click app (it is a library — you write Python), and not the fastest option for plain static HTML, where a requests-based fetcher will always beat a real browser.


Reading articles is good. Building is better.

Free account = 20+ free chapters across 25 courses, with a per-chapter AI tutor. No card. Cancel anytime if you ever upgrade.

Install in 3 Commands {#install}

Answer first: pip install -U crawl4ai, then crawl4ai-setup, then crawl4ai-doctor to verify — that is the entire install, per the official docs. On our machine crawl4ai-setup finished in 52 seconds, almost all of it a 93.5 MiB Chrome Headless Shell (Chromium 149) download via Playwright.

# 1. The library (we got v0.9.2, the current release)
pip install -U crawl4ai

# 2. Browser dependencies for regular + undetected modes
crawl4ai-setup

# 3. Sanity check the whole install
crawl4ai-doctor

We ran this on Python 3.12 in a fresh venv; crawl4ai-setup finished with a clean "Post-installation setup completed!" and the doctor passed. Two version notes worth your time: pin the version in anything you deploy — the project shipped five releases between early June and mid-July 2026 (0.8.8 through 0.9.2, per the GitHub releases page) — and use a virtual environment, because the dependency stack is substantial. Optional extras exist for heavier features — pip install "crawl4ai[torch]" for PyTorch-based clustering, [transformer] for local HF models, [all] for everything (per the official installation docs) — but the base install is all this guide needs.


First Crawl: Any Page to Markdown in Six Lines {#first-crawl}

Answer first: six lines of Python turn a URL into clean markdown — our first crawl took 6.44 seconds including browser startup; repeat crawls in the same session are faster since the browser is already up.

import asyncio
from crawl4ai import AsyncWebCrawler

async def main():
    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(url="https://docs.crawl4ai.com/core/installation/")
        print(result.markdown)

asyncio.run(main())

That is the official quickstart pattern, and it works exactly as advertised. result.markdown is real markdown — headings, lists, code fences preserved — not the tag-soup text you get from naive HTML-to-text conversion. For a one-off page into a notes file, you can stop reading here.

For RAG, you should not stop here, because raw markdown still contains everything on the page: nav bars, footers, cookie banners, "edit this page" links. That junk gets embedded, retrieved, and quoted at you later. Which is why the next section is the one that matters.


fit_markdown: Cutting the Boilerplate Before It Poisons Retrieval {#fit-markdown}

Answer first: attach a PruningContentFilter and read result.markdown.fit_markdown instead — on our test page it cut 11,798 characters of raw markdown down to 3,043 (74% removed), and everything it removed was navigation and boilerplate.

from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
from crawl4ai.content_filter_strategy import PruningContentFilter
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator

prune = PruningContentFilter(
    threshold=0.45,          # lower keeps more, higher prunes more
    threshold_type="dynamic",
    min_word_threshold=5,    # drop nodes with fewer than 5 words
)
config = CrawlerRunConfig(
    markdown_generator=DefaultMarkdownGenerator(content_filter=prune)
)

# inside the crawler:
result = await crawler.arun(url=URL, config=config)
clean = result.markdown.fit_markdown   # filtered
full  = result.markdown.raw_markdown   # everything

The pruning filter scores DOM nodes by text density and link density and drops the low-value ones — no LLM involved, so it costs milliseconds. There is a second filter worth knowing: BM25ContentFilter(user_query="...", bm25_threshold=1.2) keeps only content relevant to a query, which is useful when you crawl broad pages but only care about one topic. Both attach the same way, via DefaultMarkdownGenerator(content_filter=...).

A 74% cut sounds aggressive, and on some pages it is — see limitations for when to lower the threshold. But for docs sites, blogs, and news pages, this single feature is the difference between a RAG index that answers questions and one that confidently retrieves your cookie policy. If you want the theory of why clean chunks beat big chunks, our local RAG setup guide covers it.


Reading articles is good. Building is better.

Free account = 20+ free chapters across 25 courses, with a per-chapter AI tutor. No card. Cancel anytime if you ever upgrade.

The Full Crawl-to-RAG Pipeline: Measured, Under 8 Seconds {#crawl-to-rag}

Answer first: crawl → prune → chunk → embed with Ollama's nomic-embed-text → store in ChromaDB → answer a query ran end-to-end in under 8 seconds on our Apple M3 Pro (18GB) — and every piece of it is free and local.

These are our own measurements (Crawl4AI 0.9.2, Python 3.12, macOS, August 2026), crawling the Crawl4AI installation docs page as the test document:

StageTimeDetail
Crawl + prune (1 page)6.44sincludes headless browser startup; 11,798 → 3,043 chars
Chunk~0s4 chunks of ~1,000 chars, 150 overlap
Embed (nomic-embed-text via Ollama)0.55s768-dim vectors, 4 chunks
Store (ChromaDB, persistent)0.01slocal disk
Query (embed question + search)0.03stop hit was the correct installation section
Total~7.0s$0.00

The code, condensed — this is the same architecture as our Ollama + ChromaDB RAG pipeline, with Crawl4AI replacing the file loader as the ingestion step:

import asyncio, chromadb, ollama
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
from crawl4ai.content_filter_strategy import PruningContentFilter
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator

URL = "https://docs.crawl4ai.com/core/installation/"

async def crawl_clean(url):
    prune = PruningContentFilter(threshold=0.45, threshold_type="dynamic", min_word_threshold=5)
    cfg = CrawlerRunConfig(markdown_generator=DefaultMarkdownGenerator(content_filter=prune))
    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(url=url, config=cfg)
    return result.markdown.fit_markdown

def chunk(text, size=1000, overlap=150):
    out, i = [], 0
    while i < len(text):
        out.append(text[i:i + size])
        i += size - overlap
    return out

md = asyncio.run(crawl_clean(URL))
chunks = chunk(md)

embs = [ollama.embeddings(model="nomic-embed-text", prompt=c)["embedding"] for c in chunks]

client = chromadb.PersistentClient(path="./crawl_rag_db")
col = client.get_or_create_collection("web_docs")
col.add(ids=[f"c{i}" for i in range(len(chunks))], embeddings=embs, documents=chunks)

question = "How do I install Crawl4AI and set up the browser?"
q_emb = ollama.embeddings(model="nomic-embed-text", prompt=question)["embedding"]
hits = col.query(query_embeddings=[q_emb], n_results=2)
print(hits["documents"][0][0])   # feed these chunks to your chat model as context

From here, generation is one more Ollama call with the retrieved chunks as context — the pipeline guide has that step, plus a FastAPI wrapper. We also timed the loop at corpus scale, with generation included: an 8-page deep crawl of the Crawl4AI docs (7.3s) produced 50 chunks, batch-embedding them via ollama.embed(model="nomic-embed-text", input=chunks) took 2.4s, the ChromaDB write 0.1s, and retrieving the top 4 chunks plus generating an answer with llama3.2:3b took 8.8s — 18.6 seconds total from URL to a correct, grounded answer. We asked "How do I get fit_markdown instead of raw markdown?", a question answerable only from the crawled pages, and the 3B model pointed at PruningContentFilter plus DefaultMarkdownGenerator and reproduced a working config. A model that small getting documentation questions right is retrieval doing its job, not the model being clever. If you are choosing an embedding model, nomic-embed-text is our default for a reason, but the trade-offs are in the local embeddings guide; and if ChromaDB is not your vector store, the same code shape works with anything in our vector database comparison.

Hardware note: none of this needs a GPU. The crawl is network-bound, nomic-embed-text is a 274MB model that runs fine on CPU, and ChromaDB is just disk. A modest machine from our local agent hardware guide handles the whole stack; the GPU only starts mattering at the generation step, and even there a 3B-8B model is plenty for grounded Q&A — the current picks are in our best Ollama models for 8GB VRAM rundown.


Deep Crawling: A Whole Docs Site in One Call {#deep-crawling}

Answer first: BFSDeepCrawlStrategy(max_depth=1, max_pages=8) crawled 8 pages of the Crawl4AI docs in 7.3 seconds on our machine, pruning 115,652 characters of raw markdown down to 51,048 of RAG-ready content (a 56% cut) — a whole small knowledge base in one function call.

from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
from crawl4ai.deep_crawling import BFSDeepCrawlStrategy
from crawl4ai.deep_crawling.filters import FilterChain, DomainFilter, URLPatternFilter

config = CrawlerRunConfig(
    markdown_generator=md_generator,   # same pruning setup as above
    deep_crawl_strategy=BFSDeepCrawlStrategy(
        max_depth=1,            # start page + 1 level of links
        include_external=False, # stay on the domain
        max_pages=8,            # hard cap — always set one
        filter_chain=FilterChain([
            DomainFilter(allowed_domains=["docs.example.com"]),
            URLPatternFilter(patterns=["*guide*", "*tutorial*"]),
        ]),
    ),
    check_robots_txt=True,      # defaults to False — turn it on
)

results = await crawler.arun(url="https://docs.example.com/", config=config)
for r in results:                       # a list, one result per page
    if r.success:
        index(r.markdown.fit_markdown)  # your chunk/embed/store from above

Breadth-first search, domain and URL-pattern filters, an optional score_threshold for URL relevance scoring, and stream=True if you want results as an async iterator instead of a list at the end. Three rules we would insist on: always set max_pages (depth grows link counts brutally fast), keep include_external=False unless you genuinely want to leave the site, and set check_robots_txt=True — we checked the installed v0.9.2 and it defaults to False, which is the difference between a polite corpus builder and an accidental nuisance.

This is the point where Crawl4AI stops being a scraping tool and becomes an ingestion engine — point it at your company wiki, your product docs, or a vendor's manual, and the RAG agent on top of it suddenly knows things.


Structured Extraction with Ollama (No API Key) {#llm-extraction}

Answer first: LLMExtractionStrategy with LLMConfig(provider="ollama/llama3.2") pulls structured JSON out of pages using your local Ollama model — the docs confirm local models need no API token.

Markdown is right for RAG, but sometimes you want fields — prices, specs, titles — as JSON. Crawl4AI can run an LLM over the crawled content during the crawl, and the provider string format is ollama/<model-tag>, so any model you have pulled works:

from pydantic import BaseModel
from crawl4ai import LLMExtractionStrategy, LLMConfig, CrawlerRunConfig

class Product(BaseModel):
    name: str
    price: str

strategy = LLMExtractionStrategy(
    llm_config=LLMConfig(provider="ollama/llama3.2"),  # no api_token needed locally
    schema=Product.model_json_schema(),
    extraction_type="schema",
    instruction="Extract every product name and price on the page.",
    chunk_token_threshold=1000,
    apply_chunking=True,
    input_format="markdown",
)
config = CrawlerRunConfig(extraction_strategy=strategy)
result = await crawler.arun(url=URL, config=config)
print(result.extracted_content)   # JSON matching your schema

Honest advice: use this selectively. Every chunk of every page becomes an LLM call, and on local hardware that turns a 7-second crawl into minutes on a big site. For repetitive page structures, Crawl4AI also has CSS-selector-based extraction that costs nothing — reach for the LLM strategy when the structure varies too much for selectors.


The Docker Option {#docker}

Answer first: docker run -d -p 11235:11235 --shm-size=1g unclecode/crawl4ai:latest gives you Crawl4AI as a self-hosted REST service with a dashboard at localhost:11235 — use it when the consumer is not Python.

docker pull unclecode/crawl4ai:latest
docker run -d -p 11235:11235 --name crawl4ai --shm-size=1g unclecode/crawl4ai:latest
# dashboard: http://localhost:11235/dashboard

These commands are from the project README (the docs site's installation page still shows an older experimental image tag — trust the README here). The Docker route makes sense if your pipeline is in Node or n8n-style automation and you want crawling as an HTTP endpoint rather than a library import. For a pure-Python RAG stack, pip is simpler and one less moving part.


Honest Limitations {#limitations}

Answer first: Crawl4AI is the right default for local RAG ingestion, but it is a real browser (heavy), its pruning filter can over-cut, LLM extraction is slow on local models, and none of this exempts you from robots.txt and terms of service.

  • It ships a browser. crawl4ai-setup pulled a 93.5 MiB headless Chromium on top of a substantial Python dependency stack, and every live browser instance holds real RAM while it runs. For static HTML at scale, a requests-based fetcher is far cheaper — Crawl4AI earns its weight on JavaScript-rendered pages.
  • Pruning is a heuristic, not a reader. Our 74% cut was accurate on a docs page, but density-based filtering can eat sparse-but-real content — short FAQs, tables of numbers, changelogs. Spot-check fit_markdown against raw_markdown on each new site and lower threshold if content is going missing.
  • First-crawl latency. 6.44s of our single-page time was dominated by browser startup. Batch your crawls in one session (as the deep-crawl demo does — 8 pages in 7.3s) rather than paying startup per page.
  • The release cadence is brisk. Five releases in roughly six weeks this summer (0.8.8 on June 4 through 0.9.2 on July 15, per GitHub). The APIs on this page were stable across them, but pin your version in production and read release notes before upgrading.
  • LLM extraction multiplies cost. Schema extraction calls your model per chunk. On local hardware, keep it for the pages that need it; use CSS extraction or plain fit_markdown everywhere else.
  • Docs occasionally lag the code. The installation page's Docker section still describes an older experimental image while the README documents the current one. When they disagree, the README and release notes win.
  • Anti-bot walls exist. Crawl4AI has stealth features, but heavily protected sites (login walls, aggressive bot detection) will still block or captcha you. That is a property of the modern web, not a bug in the tool.
  • Legality is on you. Respect robots.txt — remembering that check_robots_txt defaults to False — rate-limit yourself, and read the terms of the sites you crawl, especially before feeding the output into anything commercial.

None of these change the verdict. For getting web content into a local RAG pipeline at $0, nothing else we have tested combines a permissive license, a pip install, and markdown output this clean.


Sources {#sources}

  • unclecode/crawl4ai — GitHub repository: star count, license, install and Docker commands (retrieved August 2026)
  • Crawl4AI releases — version history: v0.9.2 (July 15, 2026) and the June-July release cadence
  • Crawl4AI quickstart and installation docs — config classes, raw vs fit markdown, optional extras
  • Crawl4AI deep-crawl docs — BFS/DFS/BestFirst strategies, filters, parameters
  • Crawl4AI LLM extraction docsLLMConfig Ollama provider format, no-token local usage
  • firecrawl/firecrawl and scrapy/scrapy — comparison table star counts and licenses (retrieved August 2026)
  • Our own test runs, August 2026 — all timings, character counts, and the check_robots_txt default verification on Crawl4AI 0.9.2, Python 3.12, Apple M3 Pro (18GB RAM), Ollama with nomic-embed-text and llama3.2:3b

FAQ {#faq}

🎯
AI Learning Path

Ollama’s running. Here’s what to build with it.

Go from “ollama run” to RAG apps, agents, and fine-tuned models — structured and hands-on. First chapter free.

Or own it for life — Lifetime $149 $599, pay once
Once your hardware is sorted

Stop piecing Ollama together from blog posts

Ollama Mastery is 15 chapters end to end — install, model choice, Modelfiles, GPU offload, the API, and the 20 errors that actually happen. Plus 24 more courses.

$149 once unlocks everything, forever — about $0.27/chapter for life. Prefer to spread it out? Pro is $79/year (saves 27%) or $8.99/month.
Secure checkout by Lemon Squeezy — your card never touches this siteInstant access the moment you payFirst chapter of every course is free — try before you buy

Liked this? 20 full AI courses are waiting.

From fundamentals to RAG, agents, MCP servers, voice AI, and production deployment with real GitHub repos. First chapter free, every course.

Reading now
Join the discussion

LocalAimaster Research Team

Creator of Local AI Master. I've built datasets with over 77,000 examples and trained AI models from scratch. Now I help people achieve AI independence through local AI mastery.

Build Real AI on Your Machine

RAG, agents, NLP, vision, and MLOps - chapters across 25 courses that take you from reading about AI to building AI.

Want structured AI education?

25 courses, 519+ chapters, from $9. Understand AI, don't just use it.

AI Learning Path
More on Ollama
See the full Best Ollama Models 2026 guide.

Comments (0)

No comments yet. Be the first to share your thoughts!

What is Crawl4AI and is it really free?

Crawl4AI is an open-source Python web crawler built specifically to produce LLM-ready output — clean markdown instead of raw HTML — for RAG pipelines and agents. It is Apache-2.0 licensed with about 76.1k GitHub stars as of August 2026, and the current release is v0.9.2. Everything in this guide runs locally with no API key and no paid tier: pip install, crawl, and the markdown is yours.

Does Crawl4AI work with Ollama?

Yes, in two ways. First, the simple way: crawl a page, take result.markdown, and feed it into any local RAG pipeline — chunk it, embed with an Ollama model like nomic-embed-text, and store in ChromaDB. That is the path we demo on this page, and it needs no LLM at crawl time at all. Second, Crawl4AI's LLMExtractionStrategy can call Ollama directly during the crawl to pull structured JSON out of pages: pass LLMConfig(provider="ollama/<model-tag>") and no API token is required for local models, per the official docs.

Crawl4AI vs Firecrawl — which should I use for local RAG?

Crawl4AI if you want fully local and permissively licensed. Crawl4AI is Apache-2.0 and runs entirely as a Python library on your machine. Firecrawl (about 161.5k GitHub stars as of August 2026) is bigger and excellent, but its core is AGPL-3.0 (MIT for the SDKs) and the project is built around the hosted API at firecrawl.dev — its own README says the cloud version has features the open-source version does not. Scrapy (about 63.7k stars, BSD-3) remains the classic choice for large-scale structured scraping, but it outputs raw data, not LLM-ready markdown — you build the cleaning layer yourself.

What is fit_markdown and how is it different from regular markdown output?

result.markdown.raw_markdown is the whole page converted to markdown — including navigation, footers, and cookie banners. fit_markdown is the filtered version: a content filter (PruningContentFilter or BM25ContentFilter) scores and drops the boilerplate first. On the docs page we crawled, raw markdown was 11,798 characters and fit_markdown was 3,043 — the filter cut 74% of the page and kept the actual content. For RAG that matters twice: smaller embeddings bills (in time, locally) and less junk for retrieval to trip over.

Can Crawl4AI handle JavaScript-heavy pages?

Yes — this is a core reason it exists. Crawl4AI drives a real headless browser (installed by crawl4ai-setup), so client-rendered pages, lazy-loaded content, and dynamic sites render before extraction. The cost is honest: a real browser means a 93.5 MiB Chromium download at setup (our measurement) plus meaningful RAM per running browser instance, which is why requests-based scrapers still win on pure speed for static pages.

Ready to Go Beyond Tutorials?

20 structured courses with hands-on chapters - build RAG chatbots, AI agents, and ML pipelines on your own hardware.

Bonus kit

RAG Starter Kit

Skip the setup. Complete working RAG project with Streamlit UI, FastAPI, ChromaDB. Point Crawl4AI's output at it and chat with any site. Included with paid plans, or free after subscribing to both Local AI Master and Little AI Master on YouTube.

See Plans →

Was this helpful?

📅 Published: August 23, 2026🔄 Last Updated: August 23, 2026✓ Manually Reviewed
LM

Written by the Local AI Master Team

The team behind Local AI Master

We build Local AI Master around practical, testable local AI workflows: model selection, hardware planning, RAG systems, agents, and MLOps. The goal is to turn scattered tutorials into a structured learning path you can follow on your own hardware.

✓ Local AI Curriculum✓ Hands-On Projects✓ Open Source Contributor
📚
Free · no account required

Grab the AI Starter Kit — career roadmap, cheat sheet, setup guide

No spam. Unsubscribe with one click.

🎯
AI Learning Path

Go from reading about AI to building with AI

20 structured courses. Hands-on projects. Runs on your machine. Start free.

Or own it for life — Lifetime $149 $599, pay once
Free Tools & Calculators