Tutorial

How to Add Search to Ollama After Google CSE Shutdown

Replace the deprecated Google Custom Search Engine in your Ollama setup with the Scavio API. Get structured search results for local LLMs in minutes.

Google deprecated its free Custom Search Engine JSON API tier in early 2026, breaking thousands of local LLM setups that relied on it for web grounding. If your Ollama-based assistant used CSE for search, you need a drop-in replacement that returns structured JSON, does not require OAuth, and works with a simple API key. The Scavio search endpoint accepts the same query-in, results-out pattern and returns richer data including AI Overviews and People Also Ask. This tutorial migrates your Ollama search integration from CSE to Scavio in under 20 lines of code.

Prerequisites

  • Ollama installed and running locally
  • Python 3.9+ installed
  • requests library installed
  • A Scavio API key from scavio.dev

Walkthrough

Step 1: Remove the old CSE integration

Identify and remove the Google CSE client code. The typical CSE pattern uses a cx parameter and googleapis.com endpoint that no longer works.

Python
# OLD CSE code (no longer works as of 2026):
# response = requests.get(
#     'https://www.googleapis.com/customsearch/v1',
#     params={'key': CSE_KEY, 'cx': CSE_ID, 'q': query}
# )

# NEW: Scavio replaces the above
import os, requests

SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}
URL = 'https://api.scavio.dev/api/v1/search'

Step 2: Build the Scavio search function for Ollama

Create a search function that matches the interface your Ollama tool expects. Return results in a format the LLM can parse.

Python
def web_search(query: str, num_results: int = 5) -> str:
    """Search the web and return formatted results for the LLM."""
    resp = requests.post(URL, headers=H,
        json={'query': query, 'country_code': 'us', 'num_results': num_results})
    resp.raise_for_status()
    data = resp.json()
    results = data.get('organic_results', [])
    formatted = []
    for r in results:
        formatted.append(f"Title: {r['title']}\nURL: {r['link']}\nSnippet: {r.get('snippet', '')}")
    return '\n\n'.join(formatted)

Step 3: Wire search into Ollama's tool calling

Register the search function as a tool that Ollama can call during generation. This uses Ollama's Python client with tool support.

Python
import ollama

def run_ollama_with_search(prompt: str, model: str = 'llama3.1') -> str:
    tools = [{
        'type': 'function',
        'function': {
            'name': 'web_search',
            'description': 'Search the web for current information',
            'parameters': {
                'type': 'object',
                'properties': {
                    'query': {'type': 'string', 'description': 'Search query'}
                },
                'required': ['query']
            }
        }
    }]
    response = ollama.chat(model=model, messages=[{'role': 'user', 'content': prompt}], tools=tools)
    # Handle tool calls
    if response.message.tool_calls:
        for tc in response.message.tool_calls:
            if tc.function.name == 'web_search':
                search_results = web_search(tc.function.arguments.get('query', prompt))
                # Feed results back to the model
                messages = [
                    {'role': 'user', 'content': prompt},
                    response.message,
                    {'role': 'tool', 'content': search_results}
                ]
                final = ollama.chat(model=model, messages=messages)
                return final.message.content
    return response.message.content

print(run_ollama_with_search('What are the top Python web frameworks in 2026?'))

Python Example

Python
import os, requests, ollama

SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}

def web_search(query, num=5):
    resp = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
        json={'query': query, 'country_code': 'us', 'num_results': num})
    results = resp.json().get('organic_results', [])
    return '\n'.join(f'{r["title"]}: {r.get("snippet","")}' for r in results)

def ask_with_search(prompt, model='llama3.1'):
    tools = [{'type': 'function', 'function': {
        'name': 'web_search', 'description': 'Search the web',
        'parameters': {'type': 'object', 'properties': {
            'query': {'type': 'string'}}, 'required': ['query']}}}]
    resp = ollama.chat(model=model, messages=[{'role': 'user', 'content': prompt}], tools=tools)
    if resp.message.tool_calls:
        results = web_search(resp.message.tool_calls[0].function.arguments.get('query', prompt))
        final = ollama.chat(model=model, messages=[
            {'role': 'user', 'content': prompt}, resp.message,
            {'role': 'tool', 'content': results}])
        return final.message.content
    return resp.message.content

print(ask_with_search('Latest AI news 2026'))

JavaScript Example

JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;

async function webSearch(query) {
  const resp = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST',
    headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ query, country_code: 'us', num_results: 5 })
  });
  const data = await resp.json();
  return (data.organic_results || []).map(r => `${r.title}: ${r.snippet || ''}`).join('\n');
}

async function askOllamaWithSearch(prompt) {
  const resp = await fetch('http://localhost:11434/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'llama3.1', messages: [{ role: 'user', content: prompt }],
      tools: [{ type: 'function', function: { name: 'web_search',
        description: 'Search the web', parameters: { type: 'object',
        properties: { query: { type: 'string' } }, required: ['query'] }}}]
    })
  });
  const data = await resp.json();
  if (data.message?.tool_calls?.length) {
    const results = await webSearch(data.message.tool_calls[0].function.arguments.query);
    console.log('Search results:', results);
  }
}

askOllamaWithSearch('Latest AI news 2026');

Expected Output

JSON
Search results for: 'top Python web frameworks 2026'

Title: FastAPI 1.0 Released: The Modern Python Web Framework
URL: https://fastapi.tiangolo.com/release-notes/
Snippet: FastAPI 1.0 brings stable APIs and improved performance...

Title: Django 6.0 Features Overview
URL: https://docs.djangoproject.com/en/6.0/
Snippet: Django 6.0 introduces async-first ORM and built-in AI...

Ollama response: Based on current search results, the top Python web frameworks in 2026 are FastAPI 1.0, Django 6.0, and Litestar...

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Ollama installed and running locally. Python 3.9+ installed. requests library installed. A Scavio API key from scavio.dev. A Scavio API key gives you 250 free credits per month.

Yes. The free tier includes 250 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Replace the deprecated Google Custom Search Engine in your Ollama setup with the Scavio API. Get structured search results for local LLMs in minutes.