How to Build a Search UI with the Brave Search API
Putting a search box on a site is easy. Putting one on a site that does not cost $400 a month in API calls is the actual project.
Direct answer: to build a search UI on the Brave Search API, call /res/v1/web/search from your backend with the query, count, and offset params, cache identical queries for 15-60 minutes, and render web.results. Never call the API directly from the browser — that exposes your subscription token to anyone with devtools.
Why must the call be server-side?
The token goes in an X-Subscription-Token header. Browser JavaScript cannot hide headers, and a proxied key is the single most common way search API accounts get drained.
Put a thin route in front:
// /api/search?q=...&offset=0
export async function GET(req) {
const q = new URL(req.url).searchParams.get("q") ?? "";
if (q.length < 2) return Response.json({ results: [] });
const key = "s:" + q.toLowerCase().trim();
const cached = await kv.get(key);
if (cached) return Response.json(JSON.parse(cached));
const r = await fetch(`https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(q)}&count=20`, {
headers: { "X-Subscription-Token": env.BRAVE, "Accept-Encoding": "gzip" }
});
const data = await r.json();
await kv.put(key, JSON.stringify(data), { expirationTtl: 1800 });
return Response.json(data);
}
Thirty-minute caching typically removes 60-80% of calls for a search box with natural traffic. It also makes repeat searches feel instant, which users notice.
How does pagination work?
offset takes values 0-9 and each page is up to 20 results. offset is a page index, not a result index — offset=1&count=20 is results 21-40.
The API also returns query.more_results_available. When it is false, hide the “next” button rather than showing an empty page. Users tolerate “no more results”; they do not tolerate clicking forward into nothing.
Do not deep-paginate. Results past page 5 are rarely useful, and each page is a billed query. Cap at 3 pages and offer a query refinement instead.
What is in the response that nobody uses?
The web block gets all the attention. The other blocks are free value in the same response:
faq— question/answer pairs the engine considers relevant. Excellent for a results sidebar.infobox— entity summary with a description and profiles, for knowledge-panel style results.videos— athumbnailanddurationper hit.discussions— forum threads, sometimes better than web results for opinion queries.
Rendering the FAQ block next to results increases perceived answer quality substantially, and it costs no extra query.
What about location and language?
Two params control results more than people expect: country (2-letter code) and search_lang. Without them you get results biased toward the datacentre’s default.
?q=coffee+shops&country=de&search_lang=de&ui_lang=en
country affects which results are considered relevant; search_lang filters by document language; ui_lang only affects labels in the response. Setting all three for a localised site is a five-minute change with visible results.
Local intent queries also populate locations — latitude and longitude per city — which you need for any map view.
How do Goggles work?
Goggles are community ranking rules, written in a small DSL and hosted as a URL. A custom Goggle lets you boost or demote domains for your own site.
! description: my site's ranking
$boost=3,site=docs.python.org
$downrank=5,site=pinterest.com
$discard,site=contentfarm.example
Host the file, pass its URL as goggles_id, and the ranking applies. This is the single most useful feature for a niche search product — you can suppress the content farms that dominate broad queries without building your own re-ranker.
Goggles are per-request, so you can offer a “strict mode” toggle that uses a stricter Goggle.
What does a public search box actually cost?
Free tier: 2,000 queries per month total, at one query per second. That is 66 per day — fine for a personal site, insufficient for anything with real traffic.
Paid tiers are per 1,000 queries with volume discounts. At 20,000 monthly searches with a 70% cache hit rate you make 6,000 API calls, which lands comfortably on an entry paid plan. Without caching, the same traffic is 20,000 calls and roughly triple the bill.
Cache before you optimise anything else.
Where this approach falls flat
Brave’s index is independent, which is a feature for privacy and a limitation for long-tail coverage. For very niche technical queries, a Google-backed engine often returns better results. Test 50 of your real queries before committing.
And relevance tuning is not free. The API gives you ranking from its own model. If your users need domain-specific ranking, Goggles plus a small re-ranker on the top 20 results is the path — expect that to be more work than the integration itself.
Key Takeaways
- Proxy search through your backend; a browser-exposed token will be scraped.
- Cache identical queries for 15-60 minutes — typically cuts 60-80% of calls.
offsetis a page index (0-9), andmore_results_availableshould drive the next-page button.- Set
countryandsearch_lang; without them results default to the datacentre region. - Goggles let you boost your own docs and demote content farms without building a re-ranker.
