GrounderGuides › Web grounding for RAG

Web grounding for RAG: how it works and why it matters

Published · Last updated

Web grounding is a live retrieval leg for a RAG system: at query time it searches the open web, reads the top pages, ranks them, and returns cited passages for the prompt. It matters because a static RAG index is only as fresh as your last re-ingest, and blind to anything you never indexed. This page shows how a grounding API works inside a RAG pipeline, the benefits over a static index, how web grounding compares to static RAG, and how to ground a pipeline with live web data - with Python and Node code, and a measured Grounder-vs-Tavily head-to-head that says where Tavily wins.

Transparency note: we build Grounder, one of the grounding tools discussed here, so we have a commercial interest. We have aimed for accuracy and linked claims, and the only hard numbers on this page are our own Grounder-vs-Tavily benchmark - where Tavily wins the coverage axis. Every other vendor (Tavily, Exa, Firecrawl, Serper, Brave, and the enterprise grounding products K2view, SAP AI Core, and Elastic) is described by category, not by numbers we did not measure. Always verify current pricing, limits, and behavior against each vendor's official documentation.

Quick reference (Grounder as the web-grounding leg)

What it returns
Token-capped, cited passage pack from live pages
Context control
max_tokens caps the whole response to your window
Measured lift
Local 7B model 3/8 → 7/8 correct, zero context overflows
Pricing
Flat monthly - $9 / $19 - not per-call metered
Free tier
1,500 pages/month (email only, no card)

What web grounding for RAG is, and why static indexes go stale

Web grounding is the practice of retrieving evidence from the live web at query time and feeding it to the model alongside its prompt, so a generated answer is anchored to real, current sources rather than to the model's training data. In a RAG system it is a second retrieval leg. Classic RAG embeds your documents into a vector store and retrieves the nearest chunks - fast, private, and cheap to query, but frozen at the moment you last ingested. The web moves after that: prices change, docs get versioned, incidents happen, new pages appear that were never in your corpus. A grounding step closes that gap by searching the open web, reading the top results, and returning ranked passages your pipeline can inject next to the vector-store context. The word grounding is used for internal-document RAG too - K2view, SAP AI Core, and Elastic all ship "grounding" that anchors answers in your documents - but those are still static indexes. This page is about the leg that reaches the open web, which those products do not give you.

How a grounding API works in a RAG system

A grounding API drops into the retrieval step of a RAG pipeline. It does the search-read-rank work a raw search index leaves to you, and hands back something already shaped for a prompt. The stages:

The retrieval leg: search, then read

Given the user query (or an agent's sub-query), the API first runs a web search to find live candidate sources, then fetches the top pages and strips them to clean text. This is the leg a static index cannot provide - it discovers pages that were never in your corpus and reads them on demand.

Ranking and fitting to the window

Full pages are far too long to paste into a prompt, so the API chunks the fetched text and re-ranks the chunks for relevance to the query, then keeps only the top passages. The step that most tools skip is the last one: capping the pack to a token budget so it fits your model's context window. Grounder's deep_search does all of this in one call - it searches, reads up to roughly the top ten pages, chunks and MMR-ranks them, and returns a token-capped pack via max_tokens.

Where it plugs into your existing RAG

The grounding pack merges with whatever your vector store returned, and the combined context goes into the prompt. Each passage carries its url and a relevance score, so you can cite sources, dedupe against your index, or drop low-score chunks before the prompt. With Grounder the response is a .passages array; you iterate it exactly like vector-store hits.

Web grounding vs static RAG

These are not competitors - most production systems run both - but they trade off along clear axes. Static RAG wins on speed, cost, and privacy; web grounding wins on freshness and coverage. Managed enterprise grounding products sit on the static side: they index your documents well but do not reach the open web.

ApproachRetrieves fromFreshnessCoverageFits a window?Cited?
Static vector RAGYour embedded docsLast re-ingestOnly what you indexedYou chunk itYou add it
Managed doc grounding (K2view, SAP AI Core, Elastic)Your enterprise docsRe-ingest cadenceYour knowledge baseManagedManaged
Raw web search API (Serper, Brave)Live web (links)LiveOpen webYou fetch + chunkYou add it
Agent search API (Tavily, Exa)Live web + answerLiveOpen webNo (uncapped)Partial
Grounder deep_search (ours)Live web, cited packLiveOpen webYes (max_tokens)Yes, per passage

The practical read: keep your vector store for private and high-volume internal knowledge, and add a web grounding leg for anything time-sensitive or outside your corpus. The choice inside the web-grounding column is whether the tool returns raw links (you build the rest), a full answer at arbitrary length, or a token-capped pack that already fits your window.

Benefits of using a grounding API in RAG

A grounding API earns its place by removing two kinds of work: the freshness pipeline you would otherwise maintain, and the search-read-rank plumbing you would otherwise hand-roll. Concretely:

Grounding a RAG pipeline with live web data: Python and Node

The web-grounding leg is a search to discover live sources and a deep_search to turn the top pages into a token-capped, cited pack. Grounder is an MCP server and a plain REST API; both endpoints take a Bearer key. Merge the returned .passages with your vector-store hits before the prompt.

Python (production-shaped: env key, timeout, explicit error surface):

import os
import requests

BASE = "https://grounder.dev"
HEADERS = {
    "Authorization": f"Bearer {os.environ['GROUNDER_KEY']}",
    "Content-Type": "application/json",
}

def web_search(query: str, timeout: float = 30.0) -> dict:
    """Discover live sources for `query` (Google results + snippets)."""
    r = requests.post(
        f"{BASE}/v1/search",
        json={"query": query},
        headers=HEADERS,
        timeout=timeout,
    )
    r.raise_for_status()
    return r.json()

def ground(query: str, max_tokens: int = 600, timeout: float = 60.0) -> list[dict]:
    """Return a token-capped, cited web-grounding pack for `query`."""
    r = requests.post(
        f"{BASE}/v1/deep_search",
        json={"query": query, "max_tokens": max_tokens},
        headers=HEADERS,
        timeout=timeout,
    )
    r.raise_for_status()          # 4xx/5xx -> exception, not silent bad data
    return r.json()["passages"]

def build_context(query: str, vector_hits: list[str]) -> str:
    """Merge the live web-grounding pack with your existing vector-store hits."""
    web = ground(query)
    web_block = "\n\n".join(f"[{p['score']}] {p['url']}\n{p['text']}" for p in web)
    return "\n\n".join(vector_hits) + "\n\n--- live web ---\n\n" + web_block

if __name__ == "__main__":
    ctx = build_context("latest pricing for the acme api", vector_hits=[])
    print(ctx)

Node.js (same flow, native fetch, explicit error on non-2xx):

const BASE = "https://grounder.dev";
const HEADERS = {
  "Authorization": `Bearer ${process.env.GROUNDER_KEY}`,
  "Content-Type": "application/json",
};

async function ground(query, maxTokens = 600) {
  const res = await fetch(`${BASE}/v1/deep_search`, {
    method: "POST",
    headers: HEADERS,
    body: JSON.stringify({ query, max_tokens: maxTokens }),
  });
  if (!res.ok) {
    throw new Error(`grounder ${res.status}: ${await res.text()}`);
  }
  const { passages } = await res.json();
  return passages;
}

// Merge the live web-grounding pack with your vector-store hits.
async function buildContext(query, vectorHits = []) {
  const web = await ground(query);
  const webBlock = web.map((p) => `[${p.score}] ${p.url}\n${p.text}`).join("\n\n");
  return [...vectorHits, "--- live web ---", webBlock].join("\n\n");
}

const ctx = await buildContext("latest pricing for the acme api");
console.log(ctx);

Over MCP, the same tools (web_search, fetch, deep_search, research) register in any MCP client, so an agent can call the grounding leg directly. Full parameters are in the docs.

The context-window overflow problem web grounding creates

Adding a live web leg introduces a failure the vector store never did: real pages are long. A static chunk from your index is sized by your ingest config; a freshly fetched web page is whatever length the publisher wrote. Paste two or three of them into a small model's window and the prompt overflows - the model returns nothing, truncates mid-answer, or errors. This is the single most common reason a local-LLM RAG setup that worked on indexed chunks breaks the moment you bolt on web search. The overflow guide measures the failure in detail.

The fix is to cap the grounding pack to a token budget before it reaches the prompt. Grounder does this at the API: max_tokens bounds the entire returned pack, and the passages are already MMR-ranked so the cap keeps the most relevant evidence rather than the first N characters. In our test a token-capped pack took a local 7B model from 3/8 to 7/8 correct with zero context overflows - the difference between a grounding leg that helps and one that silently breaks generation. If you wire the leg yourself with a raw search API, this cap is the piece you own.

Grounder vs Tavily for web grounding, measured (and where Tavily wins)

Grounder is the token-capped, flat-billed grounding leg: web_search for links, fetch for one real page as clean markdown, deep_search for a cited pack, and research for a multi-step agentic run - all capped to your window with max_tokens. Here is the honest head-to-head against Tavily, including the axis where Tavily is ahead.

Hard pages read (of 19)Answers found (of 37)Context spent
Tavily132676.6k chars
Grounder103065.7k chars

Hard-page coverage: Tavily wins. On 19 deliberately hard targets, Tavily read 13, Grounder read 10. g2.com is the clearest case - Tavily returns it and Grounder cannot read it at any setting. If your grounding workload is dominated by bot-walled pages, Tavily is the better tool.

Answers per token: Grounder wins. Across 37 real pages scored on whether the sentence that answers the query survives into the returned passages, Grounder found 30 answers in 65.7k characters against Tavily's 26 in 76.6k. More answers, less context - which is exactly what a RAG prompt with a bounded window needs, because the budget cannot afford navigation and boilerplate.

Billing and privacy. Tavily meters per call; Grounder is a flat monthly price with a page budget, so a grounding loop that reads hundreds of pages does not move your bill. Grounder stores per-key billing and a domain on retrieval events, never the query, the path, or who asked. A page it could not read returns 422 fetch_failed with a reason and is not charged.

Known limitations of web grounding (and of Grounder)

The section most vendor pages skip. Some of these are limits of web grounding as a technique; the rest are honest weaknesses of Grounder specifically. Every one is a real reason to pick something else:

  1. Web grounding is slower than a vector lookup. Search-then-read costs network round trips a local index does not; for hot, private, high-volume knowledge the vector store is the right leg.
  2. Tavily reads more of the hard web - 13/19 vs Grounder's 10/19 on hard targets. Coverage of bot-walled pages is the axis Tavily leads.
  3. Grounder cannot read g2.com at any setting; Tavily can. Review-site-heavy grounding should use Tavily.
  4. Grounder resells a discovery vendor - it does not run its own index like Brave or Tavily, so it inherits that vendor's coverage limits.
  5. Near-zero distribution - Tavily has a large SDK ecosystem and many framework integrations; Grounder has an MCP server and a REST API and little else.
  6. Flat pricing is not cheapest-per-call - for tiny or occasional grounding, Serper or a self-hosted SearXNG costs less.
  7. No neural/semantic recall - if you need meaning-based retrieval where the answer is phrased unlike the page, Exa is purpose-built for it and Grounder is not.
  8. It does not replace your document store. Grounder grounds on the live web; for grounding on your own enterprise documents you still want a vector DB or a managed product like K2view, SAP AI Core, or Elastic.

Which grounding approach to pick, and when to use Grounder

The context-fit is the axis most grounding tools leave to you. A search API hands back results at any length; a scraper hands back a whole page. Grounder caps the whole grounding pack to your window with max_tokens. We measured what that is worth: a token-capped pack took a local 7B model from 3/8 to 7/8 correct with zero overflows.

Add a live web-grounding leg to your RAG

Grounder returns a cited evidence pack sized to your context window, over MCP or REST, on a flat monthly bill. Free tier: 1,500 pages a month, email only, no card.

Get a free key

Related guides

FAQ

What is web grounding for RAG?

A live retrieval leg: at query time it searches the open web, reads the top pages, and returns ranked, cited passages for the prompt. Classic RAG retrieves from a static vector index of your own documents; web grounding retrieves from the live web, so answers reflect what is true now. The two are complementary - most production systems ground on both.

How does a grounding API work in a RAG system?

It sits in the retrieval step: run a web search to find live sources, fetch the top pages into clean text, chunk and re-rank for relevance, and return a token-capped pack of cited passages that you inject next to your vector-store context. With Grounder that is one deep_search call returning a .passages array, capped by max_tokens.

What is the difference between web grounding and static RAG?

Static RAG retrieves from a prebuilt vector index - fast and private but only as fresh as your last ingest. Web grounding retrieves from the live web at query time - always current and unbounded in coverage but slower per call. Managed products like K2view, SAP AI Core, and Elastic ground on your own documents; they are still static indexes and do not replace a live web leg.

Does web grounding replace my vector database?

No. Keep the vector store for private, high-volume internal knowledge - it is fast and cheap to query. Web grounding covers the gap it cannot: fresh facts, long-tail topics, and anything published after your last re-index. Run both retrieval legs and merge before the prompt.

Why does live web grounding overflow my context window?

Because real pages are long. Most tools return content at whatever length it happens to be, so a few pages exceed a small model's window and it returns nothing or truncates. The fix is a token-capped pack sized to your window - Grounder caps the whole response with max_tokens, which took a local 7B model from 3/8 to 7/8 correct with zero overflows.

Which grounding tool should I use for a RAG pipeline?

Match the tool to the axis. Widest hard-page coverage: Tavily and Exa. Clean markdown to ingest: Firecrawl. Cheap raw links: Serper or Brave. Grounding on your own docs: K2view, SAP AI Core, or Elastic. A token-capped cited pack that fits a small window on a flat bill: Grounder. Verify current specifics on each vendor's docs.

Methodology: hard-page numbers from bench/hardweb.py, passage numbers from a 37-page rerank corpus, both run 2026-07-22. Grounder is a young product reselling a discovery vendor, with near-zero distribution next to Tavily's ecosystem, and it grounds on the live web rather than your own document store - those gaps are real and are the honest cost of picking it for a grounding leg today. Last updated July 2026 - see the docs for current parameters.