Skip to main content
Turn a website into a knowledge base your LLM can search: Crawl finds the pages, Batch returns each one as clean markdown, and your code splits the markdown by headings, embeds the chunks and stores them. Ask a question, retrieve the best chunks, and send them to your model with their source URLs. Uses: Crawl, Batch with response_type=markdown and Adaptive Stealth Mode (mode=auto)

How it works

  1. Crawl finds the pages. Crawl starts at one URL, follows links on the same domain, and keeps the URLs that match include_patterns.
  2. Batch fetches every page as markdown. One Batch job runs every URL with response_type=markdown and mode=auto. Headings, lists, links and tables stay; scripts and styling go.
  3. Your code chunks by headings. Each # to ###### heading starts a new chunk, and the chunk keeps its heading path (Product > Description) as context. Text before the first heading, usually site navigation, is skipped.
  4. Your embedding model indexes the chunks. Every chunk becomes a vector in your store, with its URL and heading as metadata.
  5. Search returns the best chunks. A question is embedded the same way, and the closest chunks go into your LLM prompt.
Steps 1 and 2 are Zenrows. Steps 3 to 5 are yours to adapt: the chunker below is complete, and the embedding function and store are pluggable.

Ask your AI agent

With the Zenrows MCP server connected to Claude, Cursor or any MCP client, paste this prompt. Your agent picks the right Zenrows tools and settings on its own.
For a full site, ask the agent to crawl every page and scrape them in one batch: the pages arrive as markdown, ready to chunk.

Build the index

Install the Zenrows SDK with pip install zenrows. The script crawls three product pages, fetches them as markdown, chunks them and searches them. Raise max_items to index a whole site.
Python (SDK)
The embed() function above is a dependency-free stand-in so the script runs as pasted. It matches words, not meaning: swap it for a real embedding model before you rely on the results.

Example output

The top hit is the jacket’s Description section, which lists “95% Organic Cotton / 5% Spandex”.

Plug in your embedding model and vector store

These two snippets are one choice among many: use the embedding model and vector database your stack already has. Keep the chunk’s url and heading as metadata, so every answer can cite its source. An embedding model. Replace embed() with a call to your provider. With OpenAI (pip install openai, OPENAI_API_KEY set):
Python
A vector database. Replace the in-memory store and search() with your database. With Chroma (pip install chromadb), passing the vectors from embed():
Python
Then put the retrieved chunks in your prompt, each with its URL, and ask the model to answer from them only.

Customize it

Troubleshooting

  • The crawl keeps fewer pages than expected: include_patterns also decides which links Crawl opens. Add the patterns of the listing or index pages that link to your content, or remove the patterns and use exclude_patterns instead.
  • Chunks contain menus and footers: they sit under a heading inside the page template. Drop chunks whose heading matches template sections, or filter lines that are only links.
  • Answers cite the wrong page: chunks are too large and mix topics. Lower max_chars so each chunk covers one idea.
  • Some Batch tasks failed: rerun only the failures with job.retry_failed(). Successful results carry over.

Turn any web page into LLM-ready markdown

How response_type=markdown works on one page.

Map every URL on a website

Run Crawl on its own to list a site’s pages.

Build a research agent with live web data

Let an LLM read the web on demand instead of from an index.

Scrape a list of URLs

Send thousands of URLs as one Batch job.