Tutorial15 min read

AI Web Crawlers: Crawl4AI and LLM-Ready Crawling

Short answer

An AI web crawler is a crawler built to feed language models: it follows links like any crawler, renders JavaScript pages in a real browser, and returns each page as clean Markdown, or as JSON that an LLM extracted, ready for retrieval (RAG), AI agents or datasets. For a Python RAG pipeline you run yourself, Crawl4AI (Apache-2.0, Python 3.10+) turns a whole site into Markdown: BFSDeepCrawlStrategy(max_depth=2, max_pages=50) follows the site's links and returns one Markdown result per page, with its URL. If you would rather not run browsers at all, a hosted crawl API does the same for a fee per page, and for single URLs Jina Reader (https://r.jina.ai/<url>) returns Markdown with no crawl (compared below). ProxyField residential proxies plug into Crawl4AI's proxy_config from $1.95/GB; start with the Easy Trial: 1 GB for $2.95.

residential IPs
412M+
from, traffic never expires
$1.95/GB
Easy Trial
1 GB for $2.95
On this page 13 sections
  1. Two meanings of "AI web crawler"
  2. How an AI crawler differs from a classic crawler
  3. What Crawl4AI does
  4. Install Crawl4AI and crawl one page through a proxy
  5. Crawl a whole site into Markdown files
  6. Prepare the crawl for RAG
  7. Extract structured data with an LLM, or without one
  8. Crawl4AI vs Scrapy
  9. Other ways to crawl for AI
  10. Proxies for AI web crawlers
  11. Crawl politely
  12. Sources
  13. AI Web Crawlers FAQ
Python
import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
from crawl4ai.deep_crawling import BFSDeepCrawlStrategy

async def main():
    config = CrawlerRunConfig(deep_crawl_strategy=BFSDeepCrawlStrategy(max_depth=2, max_pages=50))
    async with AsyncWebCrawler() as crawler:
        pages = await crawler.arun("https://example.com/docs/", config=config)  # one result per page
        return [(p.url, p.markdown.raw_markdown) for p in pages if p.success]

docs = asyncio.run(main())

The full script, with a proxy and one Markdown file per page, is below.

Two meanings of "AI web crawler"

The phrase names two different things, and search results mix them.

MeaningWho runs itWhat it doesRead more
A crawler for AI pipelinesYouCrawls the sites you choose and turns the pages into Markdown or structured data for a modelThis page
An AI company's crawlerOpenAI, Anthropic, Common Crawl and othersCollects pages for model training or for AI search, under its own user agentAI crawlers and the sites you scrape, web scraping for AI training

This page is about the first kind: tools you run. The second kind matters to you as a site owner, or because sites that block AI companies' bots now challenge other automated traffic more often.

How an AI crawler differs from a classic crawler

An AI crawler keeps the crawling part of a classic crawler and changes what comes out: text a model can read, instead of raw HTML or fields you mapped by hand.

FeatureClassic crawler (Scrapy, Crawlee)AI web crawler (Crawl4AI)
FetchingPlain HTTP requests; a browser only if you add oneA headless browser for every page by default
OutputThe items your code extracts, as JSON or CSVMarkdown with headings, tables and links, plus cleaned HTML, links and media
ExtractionCSS or XPath selectors you write per siteCSS or XPath schemas, or an LLM that fills a JSON schema you describe
Which pages nextRules and link extractors you defineBreadth-first, depth-first or best-first strategies, and an adaptive mode that stops when it has enough on a query
Cost per pageBandwidth and a little CPUA browser page, plus model tokens if an LLM extracts

What does not change: the crawler still downloads every page from a website, so it meets the same rate limits, blocks and robots.txt rules as any other crawler. For the basics of crawling, see what a web crawler is.

What Crawl4AI does

Crawl4AI turns pages into input for language models, and its documentation groups the features in five areas:

  • Markdown generation. Clean Markdown that keeps headings, lists, tables and code blocks. "Fit Markdown" filters drop menus, footers and boilerplate, and links can become a numbered reference list.
  • Structured extraction. CSS and XPath schemas extract fields with no LLM at all; generate_schema can write such a schema once from a description; LLMExtractionStrategy sends the page to a model and asks for JSON that matches your schema.
  • Browser control. Chromium, Firefox and WebKit through Playwright, sessions that keep state across steps, persistent profiles, custom headers and user agents, and proxies with authentication and rotation.
  • Crawling. Deep crawls (breadth-first, depth-first, best-first) with page and depth limits, URL discovery from sitemaps and Common Crawl, arun_many() for lists of URLs, caching, screenshots and PDFs.
  • Ways to run it. A Python library, a command line tool (crwl), and a Docker server with a REST API and an MCP endpoint for AI agents.

Is it free? The library is free and open source under Apache-2.0, and its README asks for attribution (a badge or a link). Your costs are the machines that run the browsers, the model tokens if you use LLM extraction, and proxies once a site starts limiting you. The project also sells a hosted service; this page covers only the open-source library.

Install Crawl4AI and crawl one page through a proxy

Install the package, then let its setup command download the browser once:

Shell
pip install -U crawl4ai
crawl4ai-setup      # installs the browser
crawl4ai-doctor     # checks the installation

Crawl4AI's documentation recommends setting the proxy per request, in CrawlerRunConfig.proxy_config. The example below sends the page through the ProxyField gateway and prints the start of the Markdown:

Python
import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, ProxyConfig

proxy = ProxyConfig(
    server="http://gate.proxyfield.io:7000",
    username="<login>-country-us-city-new_york",
    password="<password>",
)

async def main():
    config = CrawlerRunConfig(proxy_config=proxy, check_robots_txt=True)
    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(url="https://example.com", config=config)
        print(result.success, result.url)
        print(result.markdown.raw_markdown[:500])

asyncio.run(main())

Replace <login> and <password> with your credentials. <login>-country-us-city-new_york asks for an exit IP in New York, United States; the later examples write the username as <login>. Region, session and session time go in the same username: -region-<region>, -session-<id> and -ttl-<seconds> (30 to 129,600 seconds, 20 minutes by default), as in <login>-country-us-region-new_york-city-new_york-session-he9f2qga-ttl-600; every part after the login is optional.

Three things to know about proxies in Crawl4AI:

  • One gateway is enough for rotation. proxy_config also takes a list of proxies, tried in order, and proxy_rotation_strategy rotates through a list. With a rotating gateway you do not need either: in rotating mode, ProxyField gives every request a new IP behind the same address.
  • Sessions need the same IP. When a crawl logs in or clicks through steps that belong together, keep one IP with a sticky session (30 seconds to 36 hours on ProxyField) instead of a new IP per request.
  • SOCKS5 strings are accepted. ProxyConfig.from_string accepts http://user:pass@host:port and socks5://host:port strings. ProxyField's SOCKS5 runs on the same gate.proxyfield.io:7000 as HTTP and HTTPS, with the same username and password.

Crawl a whole site into Markdown files

A deep crawl starts from one URL, follows the links it finds and returns one result per page. This example stays on the starting domain, goes 2 levels deep, stops at 50 pages and writes each page to a Markdown file:

Python
import asyncio, pathlib, re
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, ProxyConfig
from crawl4ai.deep_crawling import BFSDeepCrawlStrategy

async def main():
    config = CrawlerRunConfig(
        deep_crawl_strategy=BFSDeepCrawlStrategy(max_depth=2, include_external=False, max_pages=50),
        proxy_config=ProxyConfig(server="http://gate.proxyfield.io:7000", username="<login>", password="<password>"),
        check_robots_txt=True,
    )
    out = pathlib.Path("pages")
    out.mkdir(exist_ok=True)
    async with AsyncWebCrawler() as crawler:
        results = await crawler.arun(url="https://example.com/docs/", config=config)
        saved = 0
        for r in results:
            if r.success:
                name = re.sub(r"[^a-z0-9]+", "-", r.url.lower()).strip("-")[:80]
                (out / f"{name}.md").write_text(f"<!-- {r.url} -->\n" + r.markdown.raw_markdown)
                saved += 1
        print(saved, "pages crawled,", len(results) - saved, "failed")

asyncio.run(main())

Set max_pages before you start: its default is no limit, so the crawl keeps going as long as it finds new links within max_depth. More on depth and limits: how to crawl a website.

What a run gives you (the shape; file names and text come from the site you crawl):

$ python crawl_site.py
48 pages crawled, 2 failed

$ ls pages | head -3
https-example-com-docs.md
https-example-com-docs-getting-started.md
https-example-com-docs-install.md

$ head -6 pages/https-example-com-docs-install.md
<!-- https://example.com/docs/install -->
# Install

Install the package with pip:

    pip install example

Each file is one page: its URL on the first line, then the page's headings, lists, tables and code as Markdown, ready for the RAG steps below.

When a site publishes a sitemap, list its URLs first and crawl exactly those: you see the page count before you spend anything, and pages that no link reaches are included. Crawl4AI's AsyncUrlSeeder reads the sitemap, pattern keeps one section, and arun_many crawls the list:

Python
import asyncio, pathlib, re
from crawl4ai import AsyncUrlSeeder, AsyncWebCrawler, CrawlerRunConfig, ProxyConfig, SeedingConfig

async def main():
    async with AsyncUrlSeeder() as seeder:
        found = await seeder.urls("example.com", SeedingConfig(source="sitemap", pattern="*/docs/*", max_urls=500))
    urls = [u["url"] for u in found if u["status"] != "not_valid"]
    print(len(urls), "URLs in the sitemap")

    config = CrawlerRunConfig(
        proxy_config=ProxyConfig(server="http://gate.proxyfield.io:7000", username="<login>", password="<password>"),
        check_robots_txt=True,
        stream=True,  # handle each page as it finishes
    )
    out = pathlib.Path("pages")
    out.mkdir(exist_ok=True)
    saved = 0
    async with AsyncWebCrawler() as crawler:
        async for r in await crawler.arun_many(urls, config=config):
            if r.success:
                name = re.sub(r"[^a-z0-9]+", "-", r.url.lower()).strip("-")[:80]
                (out / f"{name}.md").write_text(f"<!-- {r.url} -->\n" + r.markdown.raw_markdown)
                saved += 1
    print(saved, "pages crawled")

asyncio.run(main())

source="sitemap" is the fastest source in Crawl4AI's documentation; max_urls=-1 means no limit. Each item the seeder returns is a dictionary with url and status (valid, not_valid or unknown). The seeder reads the sitemap directly; the page fetches go through the proxy in proxy_config.

Prepare the crawl for RAG

Do not embed the crawl as it comes. Four steps make the Markdown retrievable and citable:

  1. Keep the source

    Store each page's URL and title with every chunk, so answers can link back.

  2. Drop duplicates

    The same page often appears under several URLs (tracking parameters, print versions); hash the Markdown and keep the first copy.

  3. Split at headings

    Chunk by #, ## and ### sections, and split only long sections further, so each chunk covers one topic.

  4. Cut the noise first

    Crawl4AI's "fit Markdown" filters remove menus and footers before you chunk.

Python
import hashlib, re

def rag_chunks(results, max_chars=4000):
    seen, chunks = set(), []
    for r in results:
        if not r.success:
            continue
        md = r.markdown.raw_markdown
        digest = hashlib.sha256(md.encode()).hexdigest()
        if digest in seen:                      # 2. the same page under another URL
            continue
        seen.add(digest)
        title = (r.metadata or {}).get("title") or r.url
        for section in re.split(r"\n(?=#{1,3} )", md):   # 3. one chunk per heading
            for i in range(0, len(section), max_chars):
                text = section[i:i + max_chars].strip()
                if text:
                    chunks.append({"text": text, "url": r.url, "title": title})  # 1. source kept
    return chunks

Each dictionary is ready for your embedding model and vector store (LangChain, LlamaIndex or your own code): embed text and keep url and title as metadata. Re-crawl on a schedule and replace a page's chunks when its hash changes.

Extract structured data with an LLM, or without one

Crawl4AI has two ways to turn pages into fields, and the cheaper one does not use a model.

Without an LLM. JsonCssExtractionStrategy takes a schema of CSS selectors (a base selector for each item and a list of fields) and returns JSON. It is fast, exact and costs nothing per page, but you maintain the selectors.

With an LLM. LLMExtractionStrategy sends the page, as Markdown by default, to a model with your schema and instruction. It works with any provider that LiteLLM supports, through a provider string such as openai/gpt-4o-mini or, for a local model, ollama/llama3.3:

Python
import asyncio, os
from pydantic import BaseModel
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, LLMConfig, LLMExtractionStrategy, ProxyConfig

class Product(BaseModel):
    name: str
    price: float
    currency: str
    in_stock: bool

strategy = LLMExtractionStrategy(
    llm_config=LLMConfig(provider="openai/gpt-4o-mini", api_token=os.getenv("OPENAI_API_KEY")),
    # a local model instead: LLMConfig(provider="ollama/llama3.3", api_token="no-token")
    schema=Product.model_json_schema(),
    extraction_type="schema",
    instruction="Extract every product on the page with its price, currency and stock status.",
)

async def main():
    config = CrawlerRunConfig(
        extraction_strategy=strategy,
        proxy_config=ProxyConfig(server="http://gate.proxyfield.io:7000", username="<login>", password="<password>"),
    )
    async with AsyncWebCrawler() as crawler:
        result = await crawler.arun(url="https://example.com/category/shoes", config=config)
        print(result.extracted_content)

asyncio.run(main())

Long pages are split into chunks (chunk_token_threshold, apply_chunking) so they fit the model's context. A practical pattern: use the LLM on a few pages to learn the layout, or let generate_schema write a CSS schema, then run the schema on the rest. Check a sample of the LLM's output against the pages, because models can return plausible values that are not on the page.

Crawl4AI vs Scrapy

Scrapy is the stronger choice for large crawls of plain HTML, and Crawl4AI for JavaScript pages and output that goes straight into a model.

FeatureCrawl4AIScrapy
LicenseApache-2.0 (PyPI)BSD-3-Clause (PyPI)
Python3.10 or newer3.10 or newer
How pages are fetchedA headless browser (Playwright)Plain HTTP; JavaScript needs an add-on such as a headless browser
What you getMarkdown, cleaned HTML, links, media, screenshotsThe items your callbacks yield, exported as JSON, CSV or XML
ExtractionCSS or XPath schemas, or an LLM with a JSON schemaCSS or XPath selectors in your code; any LLM step is yours to add
Crawl controlDeep crawl strategies, page limits, URL seeding from sitemapsScheduler, link extractors and crawl rules, duplicate filter, retries, item pipelines, middlewares
robots.txtChecked only with check_robots_txt=True (default off)Obeyed in every project scrapy startproject creates (ROBOTSTXT_OBEY = True)
Proxiesproxy_config per run, a list, or a rotation strategyThe proxy key in each request's meta
Cost per pageHigher: a browser page per URLLower: one HTTP response per URL
Best forJavaScript sites, RAG and agents, small to medium crawlsHigh-volume crawls of HTML pages with stable layouts

You do not have to pick one for a whole project. A common split: Scrapy crawls and discovers URLs cheaply, and Crawl4AI renders and converts the pages that need a browser or need to go to a model. For Scrapy against Python's simplest parser, see Scrapy vs Beautiful Soup.

Other ways to crawl for AI

Crawl4AI is one of five ways to get a site into LLM-ready Markdown. The choice comes down to who runs the browsers and who pays for them:

OptionWho runs the browsers and IPsWhat you payChoose it when
Self-hosted AI crawler (Crawl4AI)YouYour machines, proxies, model tokens if an LLM extractsYou want control of the data and the cost per page, and can run Playwright
Open-source crawl server (Firecrawl, self-hosted, AGPL-3.0)YouYour machines and proxiesYou want a crawl API of your own; its managed proxy layer stays with the hosted service, so you bring proxies (setup)
Hosted crawl APIThe vendorA fee per page or per creditYou want a crawl job in a few lines of code and no browsers to manage
Single-page Markdown converter (Jina Reader: prepend https://r.jina.ai/ to a URL; Apache-2.0)The vendor, or you if you run the open-source codePer requestYou already have the URL list, or need PDFs and single pages; it converts one URL per call and does not follow links
Classic crawler plus a converter (Scrapy or Crawlee)YouBandwidth and a little CPUMost pages are plain HTML and the crawl is large
  • Other open-source AI scrapers. Libraries that send a page to an LLM with a prompt, or let an LLM drive a browser: open-source AI scraping libraries compares them with code.
  • ProxyField's own API. The web scraping API is designed to fetch any URL as plain HTTP or with JavaScript rendering, billed on successful results only; it is in development (Contact sales).
  • MCP servers for agents. An agent calls a crawler as a tool: web crawl and scraping MCP servers.

For a ranking of AI scraping tools by use case, see AI scraping tools compared.

Proxies for AI web crawlers

A browser crawl sends many requests to one site from one IP, so beyond a few hundred pages you need rotating IPs, a realistic pace and, for some sites, a location close to the audience.

  • Rotate for independent pages. A crawl of product or article pages can take a new IP on every request. ProxyField does this through one gateway, gate.proxyfield.io:7000, unless you ask for a sticky session.
  • Stick for sessions. Logins and multi-step flows keep one IP with a sticky session, from 30 seconds to 36 hours.
  • Pick the location. Prices, search results and content change by country; ProxyField has 412M+ residential IPs in 195+ countries, with targeting by country, region (state) and city.
  • Budget the traffic. Residential traffic is billed per GB, and a rendered page downloads its scripts, images and fonts as well as its HTML. Measure the average page weight on a sample of your targets, and block images and media you do not need. As an example, 10,000 pages at 2 MB each come to about 20 GB, which costs $55.80 at ProxyField's $2.79/GB rate for 10-49 GB. The per-GB rate for every volume band is on the pricing page.
  • Keep threads in check. ProxyField allows unlimited concurrent threads, but a site does not: cap concurrency per domain and add delays.

If the crawl still meets 403 errors or challenge pages, read how to avoid getting blocked while scraping before you add more IPs.

Get started: residential proxies cost $2.95/GB for 1 GB and fall to $1.95/GB from 1,000 GB, with no subscription; start with the Easy Trial: 1 GB for $2.95. Traffic never expires, and all purchases are final.

Crawl politely

An AI crawler is still a crawler, and the same rules apply:

  • Turn on check_robots_txt=True in Crawl4AI, because it is off by default, and respect the rules that apply to all agents: how to check if a website allows scraping.
  • Crawl public pages only, never data behind logins you are not entitled to, as ProxyField's acceptable use policy also requires.
  • Keep the pace human-scale and identify a contact if you crawl a site often.
  • Using crawled pages to train or ground a model raises copyright and personal-data questions of its own: is AI scraping legal.

Sources

Read on October 23, 2026 (the PyPI versions and the max_pages default checked again on October 27, 2026):

AI Web Crawlers FAQ

What's a good AI web crawler for Python that turns a whole website into LLM-ready Markdown for RAG?

ProxyField's guide picks Crawl4AI for a pipeline you run yourself: it is free under Apache-2.0, runs on Python 3.10+, and BFSDeepCrawlStrategy(max_depth=2, max_pages=50) turns up to 50 pages of a site into one Markdown result each, with its URL. If the site has a sitemap, AsyncUrlSeeder lists its URLs first and arun_many() crawls exactly those. Keep the URL and title with each chunk, drop duplicate pages and split at headings before you embed; for single URLs rather than a whole site, Jina Reader returns Markdown per call.

What is an AI web crawler?

An AI web crawler is a crawler that turns the pages it visits into input for language models, as clean Markdown or as JSON an LLM extracted, instead of raw HTML; open-source tools such as Crawl4AI do this on your own machine and take a proxy for every request. The term is also used for the bots AI companies run to collect training data. ProxyField residential proxies (412M+ IPs, from $1.95/GB) plug into the proxy setting of crawlers such as Crawl4AI.

Is there an AI crawler for Python?

Yes. Crawl4AI is a Python library (Python 3.10 or newer) that crawls with a headless browser and returns Markdown or LLM-extracted JSON; you install it with pip install -U crawl4ai and crawl4ai-setup. You can also pair Scrapy or Crawlee with an LLM step of your own.

Is "Crawl for AI" the same as Crawl4AI?

Usually: people often type "crawl for AI" or "crawl 4 AI" when they look for Crawl4AI, the open-source crawler whose name is read that way, though the phrase can also mean crawling for AI in general. The package on PyPI is crawl4ai, and the code is on GitHub at unclecode/crawl4ai.

What is Crawl4AI used for?

Turning websites into data for AI: Markdown for RAG and AI agents, JSON extracted with CSS schemas or an LLM, and deep crawls of documentation or product sites. It also takes screenshots and PDFs, and its Docker server gives agents a REST API and an MCP endpoint.

Is Crawl4AI free?

The library is free and open source under the Apache-2.0 license, and its README asks for attribution. You still pay for the machines that run the browsers, for model tokens if you use LLM extraction, and for proxies at volume. The project also sells a separate hosted service.

Do I need an API key or an LLM to use Crawl4AI?

No. Crawling, Markdown generation and CSS or XPath extraction work without any model or key. You need an API key only for LLM extraction with a hosted model, and a local model through Ollama needs none.

Crawl4AI vs Scrapy: which should I use?

Scrapy for high-volume crawls of plain HTML pages, because one HTTP response per page costs less than a browser page. Crawl4AI for JavaScript sites and for Markdown or JSON that goes straight into a model. Many teams use Scrapy to discover URLs and Crawl4AI for the pages that need rendering.

Can Crawl4AI handle JavaScript-rendered pages?

Yes: it loads every page in a headless browser (Chromium, Firefox or WebKit through Playwright), and it can run your JavaScript, wait for an element and scroll the full page to load lazy content. That rendering costs more CPU, memory and traffic than a plain HTTP fetch.

Does Crawl4AI support proxy rotation?

Yes. proxy_config takes one proxy or a list tried in order, and proxy_rotation_strategy rotates through a list. With a rotating gateway such as ProxyField's, one ProxyConfig is enough, because in rotating mode the gateway gives each request a new IP.

Show 9 more questionsShow fewer questions

How do I crawl only the pages in a sitemap with Crawl4AI?

List the URLs with AsyncUrlSeeder and SeedingConfig(source="sitemap", pattern="*/docs/*"), then pass them to crawler.arun_many(); the script on this page prints the URL count first and writes one Markdown file per page. max_urls caps the list, and -1 means no limit.

Is Jina Reader a whole-site crawler?

No: Jina Reader converts one URL per call into Markdown when you prepend https://r.jina.ai/ to it, and it also parses PDFs, but it does not follow links. For a whole site, crawl with Crawl4AI or list the sitemap URLs and send each one.

Which proxies work best with Crawl4AI?

Rotating residential proxies for sites that limit or block datacenter traffic, and datacenter proxies for sites that do not. Use sticky sessions for logins and multi-step flows, and a country or city exit when content changes by location.

Which LLM should I use with Crawl4AI?

Any model LiteLLM supports, through a provider string such as openai/gpt-4o-mini or ollama/llama3.3. A small, cheap model is usually enough for extraction into a fixed schema; check its output on a sample of pages before you run the whole crawl.

Is Crawl4AI good for large-scale scraping?

It handles lists of URLs with arun_many(), concurrency dispatchers and caching, and it can run as a Docker server. Every page is a browser page, though, so at millions of pages a month a Scrapy or Crawlee crawl with browsers only where needed costs less per page.

Can Crawl4AI get past Cloudflare on its own?

Not reliably. It has a stealth mode and retries, but a site's bot protection still sees its IP, its request rate and its browser. Rotating residential IPs and a slower pace help; they do not promise access to every site.

Can I use Crawl4AI with RAG and LangChain?

Yes: crawl the site to Markdown, split it at headings, keep the URL and title as metadata, embed the chunks and load them into the vector store your LangChain or other RAG pipeline uses. The rag_chunks() function on this page does the splitting and drops duplicate pages.

What is LLM-ready Markdown?

Page text converted to Markdown that keeps the headings, lists, tables and links and drops scripts, styles, menus and footers. A model reads it with fewer tokens and less noise than raw HTML.

What is the difference between an AI crawler and a search engine crawler?

A search engine crawler fetches pages to index them for search results; an AI company's crawler fetches them to train models or to answer questions in an AI assistant. Both announce themselves by user agent, and sites can allow or block each one in robots.txt.

Easy Trial: 1 GB for $2.95.

Try for the price of 1 GB, no subscription, traffic never expires.