ollama web search api — the search isn't local
Ollama's web search API shipped September 2025. We knocked keyless tonight: 401 in 0.13 and 0.15 seconds. The key, the limits, and the part that isn't local.
The compressed answer: the web search API shipped September 24, 2025 as two cloud endpoints — web_search and web_fetch — behind one account key. Any model you run locally can call them as tools, and the Python/JS libraries have carried the calls since version 0.6.0. The search itself never touches your hardware: your query rides ollama.com's infrastructure and the results come back as plain JSON.
Get the key at ollama.com/settings/keys, export it as
OLLAMA_API_KEY, and POST{"query": "..."}tohttps://ollama.com/api/web_searchwithAuthorization: Bearer $OLLAMA_API_KEY. Free tier with an account, higher limits on the paid cloud. Keyless requests get a 401 in under 0.2 seconds — measured tonight, twice.
receipts last tested 2026-11-02. What you'll see below is the public record plus two live door reads we made tonight, keyless and timed. We held no API key on the bench this evening — so this piece prints the door's shape, honestly, not the results' shape. (The sibling read is yesterday's seven-night crawler census — who knocks on your doors. This one is about the door your own machine knocks on.)
How do I get an ollama web search API key?
One claim: the key is an account setting, not a config flag — there is nothing to flip in ~/.ollama, because the endpoint isn't yours. Sign in at ollama.com, open Settings → Keys, mint the key, export it. The search and fetch endpoints both read the same Bearer header:
curl https://ollama.com/api/web_search \
--header "Authorization: Bearer $OLLAMA_API_KEY" \
-d '{"query": "what is ollama?"}'
verify keyless knock → 401 {"error":"Unauthorized"} — measured 2026-11-02, 0.13s. The same header opens /api/web_fetch, which returns a page as {title, content, links} — the plain-text twin of the URL you hand it.
The official Python and JavaScript libraries have carried this since 0.6.0 — ollama.web_search(...) / client.webSearch({...}) — so if your pinned version predates that, the tool simply isn't there yet.
What are the ollama web search limits?
The honest answer is a short table, because ollama publishes less than searchers want:
| Question | Public answer |
|---|---|
| Free tier? | Yes — with an account. Their words: "a generous free tier." |
| Higher limits? | Yes — paid ollama.com/cloud subscription. |
| Searches per minute / day? | Not published anywhere. |
| Results per call? | Tunable — the agent itself picks max_results. |
The searches-per-minute number people are typing into the search bar does not exist in public. That absence is the answer — and the reason the query keeps autocorrecting itself into existence.
Does ollama web search work without an API key?
No — and the refusal is beautifully small. Both endpoints, knocked keyless tonight from here:
Twenty-six bytes. The shortest documentation page on the internet, and it works: nobody is guessing their way past that door.
How do I give a local model web search?
You wire the two calls as tools and let the model choose. The official example loop — model talks, your process runs the tool, result re-enters the context — is six working lines deep:
from ollama import chat, web_search, web_fetch
tools = {'web_search': web_search, 'web_fetch': web_fetch}
r = chat(model='qwen3:4b', messages=msgs, tools=[web_search, web_fetch], think=True)
for tc in r.message.tool_calls or []:
result = tools[tc.function.name](**tc.function.arguments)
msgs.append({'role': 'tool', 'content': str(result)[:8000]})
Two numbers matter before you run that loop. First, the calls are heavy: ollama's own docs warn the tools "can return thousands of tokens" per round and recommend a context of roughly 32,000 tokens for serious loops — a default 4k-context model will choke on the receipt pile. Second, the official example truncates each tool result to 2000 × 4 characters before re-injecting it — the context tax is real enough that even ollama's demo pays it.
Model choice: ollama recommends qwen3 and gpt-oss for tool use — small, tool-capable, and happy to run multi-turn loops.
Can I use ollama web search with MCP?
Yes — ollama ships an official MCP server example (web-search-mcp.py in the ollama-python repo), so any MCP client gets the tools over stdio, keyed by the same environment variable:
the stdio shape (Cline / Codex)
{ "mcpServers": { "web_search_and_fetch": {
"command": "uv",
"args": ["run", "path/to/web-search-mcp.py"],
"env": { "OLLAMA_API_KEY": "your_key" } } } }Codex reads the same trio from ~/.codex/config.toml as a [mcp_servers.web_search] block. One key, every client.
Is the search actually local?
Local means the weights, not the web.
Trace one loop honestly. Your machine holds the model. The moment the model decides it needs the web, your query leaves the building — crosses to ollama.com's cloud, gets searched on their infrastructure, and the receipts ride back into your context. What staying local buys you is real: the weights never leave, the inference never leaves, nobody sees your prompts to the model. What it doesn't buy: the questions you ask the web land in someone else's logs — by design, behind a key you minted on their account page.
That's the wound left open: the census work counts who knocks on our doors, and here is every local setup quietly knocking on somebody else's — cheerfully, at 0.13 seconds a knock. The next honest number is the one ollama doesn't publish: what a free-tier day of searching looks like when the loop never sleeps.