How do I migrate from the Brave Search API?
Grounder's Brave-shaped endpoint honors q, count, freshness and search_lang; offset, Goggles, extra_snippets and news search are not supported.
Last checked
To keep your Brave code, change https://api.search.brave.com/res/v1/web/search to https://api.grounder.net/compat/brave/res/v1/web/search and send a search-scoped OAuth access token; q, count, freshness and search_lang are honored. Existing legacy search keys still work.
Last checked: 20 October 2026. Disclosure: Grounder (grounder.net) publishes this page, and Brave is one of the 10 search providers Grounder routes searches to.
What changes
| Brave Search API | Grounder's Brave-shaped endpoint | |
|---|---|---|
| URL | GET https://api.search.brave.com/res/v1/web/search | GET https://api.grounder.net/compat/brave/res/v1/web/search |
| Authorization | X-Subscription-Token header with a Brave key | X-Subscription-Token header with a Grounder OAuth access token scoped to search; Authorization: Bearer and existing legacy search keys also work |
| Rate limit | 50 queries a second (Search plan) | 120 requests a minute per key, about 2 a second |
count | Maximum 20, default 20 | Default 20, up to 100 |
| Cost | $5 per 1,000 requests; $5 free credit a month, tied to attribution | First 1,000 searches free per account in total, up to 100 a day |
| Other endpoints | News, images, videos, suggest, summarizer, LLM Context, Answers | Not available: web results only |
Request parameters:
| Brave parameter | On Grounder | Note |
|---|---|---|
q | Honored | Required; site: and -site: operators become domain filters (include wins over exclude; OR between them is dropped) |
count | Honored | Default 20, up to 100 |
freshness | Honored for pd, pw, pm, py | 1, 7, 31 and 365 days; Brave's custom date ranges are not read |
search_lang | Honored | Becomes the language filter |
country, offset, safesearch, result_filter, extra_snippets, spellcheck, Goggles and any other parameter | Not supported | Ignored |
The response keeps Brave's shape: type, query (read query.original) and web.results[] with type, title, url, description, language, family_friendly, page_age (only when known), meta_url and profile, plus a grounder object with provider, found_by, licensed, rank and, for licensed results, publisher_name. extra_snippets is never returned, and offset paging does not work: raise count instead. Do not rely on other query fields such as more_results_available; they are not documented here.
Results are merged and deduplicated across providers, not taken from Brave's own index alone, so Brave's statement that its results come from its own index with no fallback to Google or Bing does not describe them. Licensed sources only is on by default for signed-up accounts, so a call can return fewer results than count.
Steps
1. Authorize HTTP
Read https://api.grounder.net/.well-known/oauth-protected-resource/v1/search, register a public OAuth client, then sign in and request scope=search for resource https://api.grounder.net/v1/search. Store the returned access token as GROUNDER_ACCESS_TOKEN and refresh it before it expires. The API docs describe the flow. Existing legacy search keys still work.
2. Change the URL and access token
- https://api.search.brave.com/res/v1/web/search
+ https://api.grounder.net/compat/brave/res/v1/web/search
Before:
curl -G https://api.search.brave.com/res/v1/web/search \
-H "X-Subscription-Token: $BRAVE_API_KEY" \
--data-urlencode "q=half-life of caffeine site:ncbi.nlm.nih.gov" \
--data-urlencode "count=5" \
--data-urlencode "freshness=pm"
After:
curl -G https://api.grounder.net/compat/brave/res/v1/web/search \
-H "X-Subscription-Token: $GROUNDER_ACCESS_TOKEN" \
--data-urlencode "q=half-life of caffeine site:ncbi.nlm.nih.gov" \
--data-urlencode "count=5" \
--data-urlencode "freshness=pm"
3. Update your code
Python:
import os
import requests
resp = requests.get(
"https://api.grounder.net/compat/brave/res/v1/web/search",
headers={"X-Subscription-Token": os.environ["GROUNDER_ACCESS_TOKEN"]},
params={"q": "half-life of caffeine site:ncbi.nlm.nih.gov", "count": 5, "freshness": "pm"},
timeout=30,
)
resp.raise_for_status()
for r in resp.json()["web"]["results"]:
print(r["url"], r["grounder"]["provider"], r["grounder"]["licensed"])
TypeScript (Node 18 or later, as an ES module):
const params = new URLSearchParams({
q: "half-life of caffeine site:ncbi.nlm.nih.gov",
count: "5",
freshness: "pm",
});
const res = await fetch(`https://api.grounder.net/compat/brave/res/v1/web/search?${params}`, {
headers: { "X-Subscription-Token": process.env.GROUNDER_ACCESS_TOKEN ?? "" },
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const data = await res.json();
for (const r of data.web.results) console.log(r.url, r.grounder.provider, r.grounder.licensed);
4. Keep Brave's results
By default Grounder sends each call to the provider, or pair of providers, most likely to answer it well. To keep Brave, set Brave to Always and Licensing to Any source on the account page, under Routing. To have Brave bill you directly, add your own Brave key in the same table. To pin one search, call the native endpoint, which returns Grounder's own response shape:
curl https://api.grounder.net/v1/search \
-H "Authorization: Bearer $GROUNDER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"query": "half-life of caffeine", "top_k": 5, "requested_provider": "brave", "routing_settings": {"licensed_only": false}}'
5. Verify
Send 10 to 20 real queries to both APIs and compare result counts and URLs. Check grounder.provider and grounder.licensed on each result; fewer results than expected usually means Licensed sources only is on. Each call is a recorded search and counts toward the 1,000 free ones. curl https://api.grounder.net/v1/providers needs no key and lists the 10 providers.
6. Use MCP instead
Add https://api.grounder.net/mcp to your MCP client and sign in with Google, GitHub or Apple. The search tool takes query, top_k, domains, days, include_text and requested_provider; steps are in Docs.
If you move to another API directly
| Brave | Tavily | Exa | Perplexity Search API |
|---|---|---|---|
q | query | query | query |
count (maximum 20) | max_results (0 to 20) | numResults (1 to 100) | max_results (1 to 20) |
country (2-character code) | country (a country name, topic general only) | userLocation | country (ISO 3166-1 alpha-2) |
search_lang | language, filter_by_language | No request field found | search_language_filter (up to 10 codes) |
freshness: pd, pw, pm, py | time_range: day, week, month, year | startPublishedDate, endPublishedDate | search_recency_filter: hour, day, week, month, year |
freshness as YYYY-MM-DDtoYYYY-MM-DD | start_date, end_date | startPublishedDate, endPublishedDate | search_after_date_filter, search_before_date_filter (M/D/YYYY) |
offset (maximum 9) | No equivalent in the spec | No pagination; raise numResults | No equivalent in the spec |
site: in q | include_domains (300), exclude_domains (150) | includeDomains, excludeDomains (1,200 each) | search_domain_filter (20 domains, allow or deny) |
goggles (custom re-ranking) | No equivalent; domain lists only | No equivalent; domain lists only | No equivalent; domain lists only |
extra_snippets | Closest: chunks_per_source (1 to 3) | Closest: contents.highlights | Closest: max_tokens_per_page |
web.results[].description | results[].content | results[].highlights or text | results[].snippet |
Brave's LLM Context endpoint, which returns extracted chunks, has no one-field equivalent; the closest are Exa's highlights, Tavily's include_raw_content and Perplexity's max_tokens. Side by side, in more depth: Tavily vs Brave, Exa vs Brave and Brave Search API alternatives.
Where Grounder fits
Grounder is a web search API and MCP server for AI agents: one search goes across 10 web search providers, results are deduplicated, and each is marked with its provider and whether it is licensed. It returns sources, not an answer. Grounder's benchmark, run by Grounder, searched 887 questions (table as of 20 October 2026 05:22 UTC):
| Row | SimpleQA correct given attempted (671 questions) | SealQA correct given attempted (216 questions) |
|---|---|---|
| Grounder optimized | 14.3% | 12.1% |
| Grounder optimized, all sources | 97.9% | 36.6% |
| Perplexity | 96.1% | 36.8% |
| Exa | 88.6% | 32.1% |
| Tavily | 86.6% | 24.5% |
| Brave | 85.2% | 16.4% |
Each provider's row is its default search. Figures are correct given attempted: the share of the questions a search answered that it got right, with a "don't know" counted as not attempted. Grounder optimized answers only from licensed sources, so it gets fewer answers right than the all-sources row, which searches every source. Grounder optimized is what a signed-up account gets by default; the all-sources row is the same routing with nothing filtered out. Both Grounder rows are routed as Grounder routes on 19 October 2026, and that routing was tuned on these same searches. Read against Brave: the all-sources row is ahead of Brave on both benchmarks, but the default row (14.3% and 12.1%) is far behind it, and Brave's own published rate limit (50 queries a second) is well above the 120 requests a minute per key here. Each question was searched once on every provider's default search (top 10 results, 60 seconds), answered by Z.ai's GLM-5.3-Flash and graded with OpenAI's SimpleQA grader, from 8 to 13 October 2026. Full method: /benchmarks. For a wider comparison, see the best search API for AI agents.
FAQ
Is there a Brave-compatible endpoint?
Yes: GET https://api.grounder.net/compat/brave/res/v1/web/search takes Brave's query parameters and returns Brave's web.results shape plus a grounder object on each result. It accepts an OAuth access token with the search scope; existing legacy search keys still work.
Which Brave parameters does it honor?
q (with site: and -site: operators), count (up to 100), freshness (pd, pw, pm, py) and search_lang. country, offset, safesearch, result_filter, extra_snippets and spellcheck are ignored.
What happens to Goggles, LLM Context and Answers?
They are not supported. The endpoint returns web results only, with no news, images, videos, suggest or summarizer either.
Is the Brave Search API still free?
Brave's pricing page lists $5 of free credit a month on the Search plan, about 1,000 requests at $5 per 1,000, and Brave's blog ties it to attributing Brave on your site. The page headlines up to $20 in free calls a month, which Brave's blog counts as $5 on each of four plans, and no longer lists the older Free plan; Brave's pages do not say what happens to subscribers on it.
Can I cache the results?
Check first. Brave's terms bar storing results without a storage-rights plan, and Grounder publishes no storage rights for the providers' results. Grounder keeps its own search records indefinitely; see /privacy.
Which Brave parameters map to Tavily, Exa or Perplexity?
q becomes query; count (maximum 20) becomes max_results (Tavily, 0 to 20), numResults (Exa, up to 100) or max_results (Perplexity, 1 to 20); search_lang becomes language (Tavily) or search_language_filter (Perplexity); freshness becomes time_range (Tavily), startPublishedDate (Exa) or search_recency_filter (Perplexity). Goggles and extra_snippets have no direct equivalent.
Next step
Your first 1,000 searches are free, up to 100 a day. No card needed. Connect an MCP client to https://api.grounder.net/mcp, or read the HTTP API docs to use OAuth.
Sources
- https://grounder.net/docs (20 October 2026)
- https://api-dashboard.search.brave.com/app/documentation/web-search/query (20 October 2026)
- https://brave.com/search/api/ (20 October 2026)
- https://brave.com/blog/most-powerful-search-api-for-ai/ (20 October 2026)
- https://docs.tavily.com/documentation/api-reference/endpoint/search (20 October 2026)
- https://exa.ai/docs/reference/search (20 October 2026)
- https://docs.perplexity.ai/docs/search/quickstart and https://docs.perplexity.ai/docs/search/filters/date-time-filters (20 October 2026)
- https://grounder.net/benchmarks and https://api.grounder.net/v1/demo/results (20 October 2026, as of 05:22 UTC)
- https://grounder.net/pricing (20 October 2026)
- https://arxiv.org/abs/2411.04368 and https://arxiv.org/abs/2506.01062 (20 October 2026)