The pipeline: from URL to vector store
A retrieval pipeline turns a list of URLs into searchable context in five steps. Fetch the page (the hard step, covered below). Clean and convert to Markdown, dropping navigation, footers, cookie banners, and scripts while keeping headings, lists, tables, and code. Chunk the Markdown into passages. Embed each chunk into a vector. Store the vectors with their source metadata in a vector database.
Markdown is the preferred intermediate format because it preserves document structure that raw text loses and strips the markup noise that raw HTML carries - a page that is 60 KB of HTML is often 4 KB of Markdown, which means more real content per token. Most managed web-data APIs can return Markdown directly, so the fetch and convert steps collapse into a single call (see the code example).
Chunking and embedding without losing structure
Chunking is where most retrieval quality is won or lost. A few rules that hold up in practice:
- Split on structure, not character count. Break on Markdown headings first, then on paragraphs, so a chunk is a coherent idea rather than an arbitrary slice. This is exactly why you convert to Markdown before chunking.
- Keep chunks at roughly 300-800 tokens with 10-20% overlap. Too large and the embedding blurs multiple topics; too small and it loses context. Overlap stops an answer from being cut in half at a boundary.
- Attach metadata to every chunk - source URL, page title, heading path, fetch date. You need it for citations, for filtering, and for re-crawl freshness.
- Dedupe by content hash. Boilerplate (the same footer or sidebar across a site) otherwise floods your index with near-identical chunks and crowds out real answers.
None of this matters if the text you chunked was wrong - which is the failure mode the next section covers.
Why pipelines that work in dev break in production
A RAG pipeline tested against a handful of friendly URLs almost always works. The same pipeline pointed at real targets degrades, and the cause is rarely the chunking - it is the fetch. Two things go wrong. First, many pages render their content with JavaScript, so a plain HTTP fetch returns an near-empty shell and you embed nothing useful. Second, sites behind bot protection (such as Cloudflare or DataDome) return a verification or challenge page instead of content.
The insidious part is that both failures return a 200 OK with a body, so a naive pipeline embeds the challenge page as if it were the article. Now your vector store is poisoned: retrieval surfaces "please enable JavaScript" and "verify you are human" as context, and the model answers from garbage. Retrieval accuracy is capped by scrape reliability, full stop.
The fix is to fetch through infrastructure that renders the page in a real browser, then returns clean Markdown - so the text entering your pipeline is the text a human would see. A managed web-data API does this in one call and, on pay-per-success pricing, you are not billed for the requests that fail, which pairs well with the retry loops a production crawler needs. For the broader context on agent-driven access, see AI agent tools and choosing a scraping API for LLM data.
