Ollama Web Search API: Python Examples and Local Model Feed
Call Ollama's web search API from Python, feed results to a local model, and build a mini agent with web_fetch. Covers auth, limits, and gotchas.

Ollama's web search API is a hosted REST endpoint at https://ollama.com/api/web_search that takes a single query string and returns up to ten results, each with a title, URL, and content snippet. You authenticate with an OLLAMA_API_KEY from a free Ollama account, pass it in the Authorization: Bearer header, and you can call it from plain HTTP, the official Python library, or the JavaScript library. A sibling endpoint, /api/web_fetch, pulls one page's content by URL.
The common pattern is to call web search, format the results into a prompt, and hand them to a local model so it can answer with current information. Ollama ships this as tool calls in the Python library, so a short loop can let a model like qwen3:4b decide when to search, when to fetch a page, and when to answer.
What the endpoint returns#
A POST to https://ollama.com/api/web_search with a JSON body containing query (string, required) and optional max_results (integer; default 5, max 10) returns an object with a results array. Each item has three fields, per the web search documentation:
| Field | Type | Notes |
|---|---|---|
| title | string | Title of the web page |
| url | string | URL of the web page |
| content | string | Relevant content snippet |
Example response shape from the docs:
{
"results": [
{
"title": "Ollama",
"url": "https://ollama.com/",
"content": "Cloud models are now available..."
}
]
}
The sibling POST https://ollama.com/api/web_fetch takes a single url and returns title, content, and a links array of URLs found on the page.
Authentication and base URL#
You need an OLLAMA_API_KEY from a free Ollama account. Set it as an environment variable or pass it in the Authorization: Bearer header. The docs show the cURL form:
curl https://ollama.com/api/web_search \
--header "Authorization: Bearer $OLLAMA_API_KEY" \
-d '{"query":"what is ollama?"}'
For the broader chat surface, the base URL depends on which client you use. Per the Ollama API documentation:
| Client | Cloud base URL | Local base URL |
|---|---|---|
| Ollama native | https://ollama.com/api |
http://localhost:11434/api |
| OpenAI compatible | https://ollama.com/v1 |
http://localhost:11434/v1 |
| Anthropic client | https://ollama.com (appends /v1/messages) |
http://localhost:11434 |
Cloud requests need the API key. Local requests to your own server do not. To use cloud models through your local server, sign in to Ollama.
Python: one-shot web search#
With the official Python library installed, the shortest call is:
import ollama
response = ollama.web_search("What is Ollama?")
print(response)
The returned object matches the REST shape: a results list of dicts with title, url, and content. To call the REST endpoint directly without the library — say, from a constrained environment — use the standard library:
import os
import json
import urllib.request
def web_search(query: str, max_results: int = 5) -> dict:
url = "https://ollama.com/api/web_search"
body = json.dumps({"query": query, "max_results": max_results}).encode()
req = urllib.request.Request(
url,
data=body,
headers={
"Authorization": f"Bearer {os.environ['OLLAMA_API_KEY']}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
if __name__ == "__main__":
print(web_search("what is ollama?"))
That uses only the standard library and the documented endpoint and headers.
Here is a runnable demo of how to format the response into lines a model can read (no network):
import json
sample = """{
"results": [
{"title": "Ollama", "url": "https://ollama.com/", "content": "Cloud models are now available..."},
{"title": "What is Ollama?", "url": "https://www.hostinger.com/tutorials/what-is-ollama", "content": "Ariffud M. 6min Read..."},
{"title": "Ollama Explained", "url": "https://www.geeksforgeeks.org/...", "content": "Ollama is a groundbreaking..."}
]
}"""
parsed = json.loads(sample)
lines = []
for r in parsed["results"]:
lines.append(f"- {r['title']}\n {r['url']}\n {r['content']}")
print("\n".join(lines))
Feeding results to a local model#
Pull a model first, then format the search results into a user message:
ollama pull qwen3:4b
from ollama import web_search, chat
results = web_search("what is ollama's new engine")
context = "\n".join(
f"- {r['title']}: {r['url']}\n {r['content']}" for r in results["results"]
)
response = chat(
model="qwen3:4b",
messages=[
{"role": "system", "content": "Use the provided web search results to answer. Cite URLs."},
{"role": "user", "content": f"Question: what is ollama's new engine?\n\nSearch results:\n{context}"},
],
)
print(response.message.content)
That is the simplest search-then-answer pattern. The model sees the snippets but cannot follow links on its own; for that you need the agent loop. For more on the chat endpoint itself, see the Ollama API guide on CoreMesh, and for running the model side locally, How to run an Ollama model locally and call it from code.
Building a mini search agent#
The docs include an example that wires web_search and web_fetch as tools the model can call. The model decides when to search, reads the results, and can fetch a page for more detail. The core of it:
from ollama import chat, web_fetch, web_search
available_tools = {"web_search": web_search, "web_fetch": web_fetch}
messages = [{"role": "user", "content": "what is ollama's new engine"}]
while True:
response = chat(
model="qwen3:4b",
messages=messages,
tools=[web_search, web_fetch],
think=True,
)
if response.message.thinking:
print("Thinking: ", response.message.thinking)
if response.message.content:
print("Content: ", response.message.content)
messages.append(response.message)
if response.message.tool_calls:
for tool_call in response.message.tool_calls:
fn = available_tools.get(tool_call.function.name)
if fn:
args = tool_call.function.arguments
result = fn(**args)
messages.append({
"role": "tool",
"content": str(result)[:2000 * 4],
"tool_name": tool_call.function.name,
})
else:
messages.append({
"role": "tool",
"content": f"Tool {tool_call.function.name} not found",
"tool_name": tool_call.function.name,
})
else:
break
A few notes from the docs: enable think=True so the model's reasoning shows up on response.message.thinking; truncate the tool result before appending, because search and fetch can return thousands of tokens; and the docs' example uses qwen3:4b as the agent model.
Limits, context length, and integrations#
The web search field max_results defaults to 5 and caps at 10. Web fetch returns the page's main content plus a links array. The docs recommend increasing the model context length to at least about 32,000 tokens for agent use, and note that cloud models run at full context length.
For pricing and quota: the official web search documentation does not list a per-call cost or a rate limit. It states that a free Ollama account is required to create an API key. If you need current usage limits, check the Ollama web search docs and your account dashboard rather than relying on a cached number.
Beyond Python and JavaScript, the same endpoints work through an MCP server. The docs show Cline and Codex configs:
{
"mcpServers": {
"web_search_and_fetch": {
"type": "stdio",
"command": "uv",
"args": ["run", "path/to/web-search-mcp.py"],
"env": {"OLLAMA_API_KEY": "your_api_key_here"}
}
}
}
[mcp_servers.web_search]
command = "uv"
args = ["run", "path/to/web-search-mcp.py"]
env = {"OLLAMA_API_KEY" = "your_api_key_here"}
Cline uses the JSON config under Manage MCP Servers. Codex reads ~/.codex/config.toml. Goose integrates through its MCP feature as well.
Common mistakes#
Forgetting the API key on cloud calls. Local chat at http://localhost:11434 does not need auth; the hosted endpoint at https://ollama.com/api/web_search does. Set OLLAMA_API_KEY or pass Authorization: Bearer ....
Using the wrong base URL for your client. The OpenAI-compatible endpoint is /v1; the native Ollama endpoint is /api; the Anthropic client appends /v1/messages to its base. Mixing these up is the usual reason a call 404s.
Truncating tool results too aggressively. The docs truncate to str(result)[:2000 * 4] characters before appending as a tool message. If you cut to a few hundred characters, the model loses the snippet it needs to answer.
Running the agent with a tiny context window. Search plus fetch plus conversation can blow past an 8K context. Bump the model's context to about 32K, or use a cloud model that runs at full context length.
Treating web_search like Google's CSE. Ollama's API is its own hosted search. The official documentation does not identify an upstream search provider. The Google Custom Search API is a separate product with its own key and quota.
Quick checklist#
- [ ] Create a free Ollama account and generate an
OLLAMA_API_KEY. - [ ] Python one-liner:
ollama.web_search("...")returns{results: [...]}. - [ ] REST:
POST https://ollama.com/api/web_searchwithAuthorization: Bearer $OLLAMA_API_KEYand{"query": "...", "max_results": 5}(default 5, max 10). - [ ] Fetch:
POST https://ollama.com/api/web_fetchwith{"url": "..."}; returnstitle,content,links. - [ ] Agent: pass
tools=[web_search, web_fetch],think=True, and truncate tool results to about 8000 characters before appending. - [ ] Set model context to about 32,000 tokens for agent use; cloud models run at full context.
- [ ] MCP integrations: Cline (JSON), Codex (
~/.codex/config.toml), Goose (MCP feature).
Quick answers
Is the Ollama web search API free?
A free Ollama account is required to create an API key. The official web search documentation does not list a per-call cost or a rate limit; check your account dashboard for current usage details.
Do I need an API key for local Ollama requests?
No. Requests to your local server at http://localhost:11434/api do not need the key. Cloud requests to https://ollama.com/api/web_search do.
What is the max number of results from web search?
max_results defaults to 5 and caps at 10, per the official docs.
Can I use Ollama web search with a Claude or Anthropic client?
The Anthropic client base URL for Ollama is https://ollama.com for cloud, and the client appends /v1/messages. Web search itself is a separate Ollama endpoint; for tool use, wire it through the Python library or the MCP server.
Does Ollama web search use the Google Search API?
The official documentation does not identify an upstream search provider. Ollama's web search is its own hosted API, separate from Google's Custom Search API.
Did this solve it?
One tap. No account.
Sorry about that. What was missing?
from 0 readers
Saved you an hour? Send a tip.
USDC or ETH on Base, Ethereum, Arbitrum and more. Keeps the notes free and the examples running.
Network
0xc783bc5c3fa14cEC3f09A22284bC91C5AF0d59e1
On a computer? Scan the code with your phone wallet, or copy the address.
Pick the network your wallet or exchange uses. USDC works on all six; ETH on Base, Ethereum, Arbitrum and Optimism. Don't send on Tron or Solana: this address doesn't exist there. Tips are optional and unlock nothing; every guide stays free.
Discussion
Start the discussion
Next note