How to Add Web Search to Your AI Agent with the Brave Search API

October 23, 2026

An LLM without search answers from its training cutoff and invents the rest. Attaching a search API gives it current facts, but only if you shape the results before they hit the context window.

Direct answer: to add live web search to an agent, call the Brave Search API at https://api.search.brave.com/res/v1/web/search with your X-Subscription-Token header, take the top 5-8 results, and pass only title, url, and description into the prompt. Free tier allows 2,000 queries per month at 1 query per second; paid plans start around $5 per 1,000 queries.

Which endpoint should you call?

Four relevant ones:

Endpoint Returns Use for
/res/v1/web/search titles, URLs, snippets general grounding
/res/v1/news/search recent articles, age field breaking topics
/res/v1/local/search places, addresses location queries
/res/v1/suggest/search autocomplete search UI, not agents

Start with web search. The news endpoint is useful when freshness matters — it returns an age field like “3 hours ago” that you can put in the prompt so the model states recency correctly.

A single request can combine them: ?q=...&result_filter=web,news returns both blocks. That is usually better than two calls, since quota is per request.

How do you make the call?

curl -s -H "X-Subscription-Token: $BRAVE_KEY" \
  "https://api.search.brave.com/res/v1/web/search?q=openai+release+notes&count=8"

In Python, keep it to a httpx call and isolate the shaping logic:

def search(q, n=8):
    r = httpx.get(URL, params={"q": q, "count": n},
                  headers={"X-Subscription-Token": KEY}, timeout=10)
    r.raise_for_status()
    return r.json().get("web", {}).get("results", [])

count maxes at 20. Beyond 8, relevance drops sharply — results 15-20 are usually noise that costs tokens and confuses the model.

Always set a timeout. Search APIs occasionally take 8 seconds, and a hanging retriever stalls the whole agent loop.

How should results be shaped for the prompt?

This is where most implementations fail. Dumping raw JSON into the context gives the model URLs, favicons, family-friendly flags, and a profile object — 400 tokens of metadata per result.

Extract three fields and format as a numbered list:

1. [title] — url
   description
2. ...

Eight results cost about 400 tokens instead of 3,200. That difference is the whole cost argument for retrieval at scale.

Also strip the description at about 200 characters. Descriptions run long, and the last third is usually boilerplate.

How do you cite and ground the answer?

Instruct the model explicitly: “Answer using only the numbered sources. If the sources do not contain the answer, say so. Cite with [n].” Without that instruction, models ignore the sources and answer from memory, and you get a plausible answer with fabricated citations.

Then post-process: parse the [n] markers and build the link list from the sources you actually passed. Never let the model generate URLs — it will invent .com domains that look plausible.

A useful check: if the model cites a source number higher than the number of results you passed, its output is unreliable. Drop it and retry.

What are the real limits?

The free tier is 2,000 queries per month, one query per second, and that rate limit is per second not per month — a burst of parallel requests returns 429s immediately. Add a simple token bucket or serialise the calls.

Commercial pricing uses a per-1,000-query model with volume tiers. At 1,000 queries per day (30k per month), you are on a paid plan and the search bill is a small line item compared with the LLM tokens each search generates.

Data for AI plans explicitly allow using results to train or ground models. The free tier does not — check which plan you are on before shipping, because the difference is contractual, not technical.

Which failure modes bite

Recency confusion. Brave returns the newest results, not the correct ones. For a query about a stable topic, results skew toward whatever was written recently, which may be wrong. Weight by domain: prefer docs, official blogs, and established outlets over content farms.

Snippet-only grounding. A 200-character description rarely contains the actual answer. For factual questions, fetch the top two result pages and extract text — two extra HTTP calls, dramatically better answers.

Query rewriting. Passing the user’s raw question verbatim gives poor results. Rewrite to keywords first with a cheap model call, then search. “What did Apple announce last week” becomes “Apple announcement” plus a date filter.

Key Takeaways

  • One endpoint does most of the work: /res/v1/web/search, with count between 5 and 8.
  • Shape results to title, URL, and a 200-character snippet — 400 tokens instead of 3,200 for eight results.
  • Free tier is 2,000 queries/month at 1 query/second; bursts get 429s, so serialise.
  • Instruct the model to cite and to refuse when sources lack the answer, then validate the citations.
  • Snippet-only grounding is weak; fetch the top two pages for real answers.