Tutorial

How to Fix OpenWebUI Web Search with Reliable API

Replace broken OpenWebUI web search with a reliable search API. Step-by-step fix for timeout and empty result errors.

OpenWebUI web search breaks frequently due to rate limits, CAPTCHAs, and provider outages. Replacing the built-in search with a structured API eliminates these failures and returns consistent JSON results. This tutorial walks through diagnosing the issue and wiring a reliable search backend into OpenWebUI at $0.005/query.

Prerequisites

  • OpenWebUI instance running
  • Python 3.8+
  • A Scavio API key from scavio.dev
  • Admin access to OpenWebUI config

Walkthrough

Step 1: Diagnose the search failure

Check OpenWebUI logs to identify the root cause of web search failures.

Python
# Common OpenWebUI search errors:
# 1. 'Search failed: timeout' - provider rate-limited
# 2. 'No results returned' - CAPTCHA blocked request
# 3. 'Connection refused' - provider endpoint changed

# Check OpenWebUI logs:
# docker logs open-webui 2>&1 | grep -i 'search'

# Test if the issue is the search provider:
import requests, os

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

# Quick test: does a structured API return results?
resp = requests.post('https://api.scavio.dev/api/v1/search',
    headers=SH, json={'query': 'python web framework', 'country_code': 'us'})
data = resp.json()
print(f'Status: {resp.status_code}')
print(f'Results: {len(data.get("organic_results", []))}')
print(f'Latency: {resp.elapsed.total_seconds():.2f}s')
if data.get('organic_results'):
    print(f'First result: {data["organic_results"][0].get("title", "")}')
    print('API is working. Issue is in OpenWebUI search config.')

Step 2: Create a search function wrapper

Build a wrapper that OpenWebUI can call for web search.

Python
import os, requests, json

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

def web_search(query, num_results=5):
    """Drop-in replacement for OpenWebUI web search."""
    try:
        resp = requests.post('https://api.scavio.dev/api/v1/search',
            headers=SH, json={'query': query, 'country_code': 'us', 'num_results': num_results},
            timeout=10)
        resp.raise_for_status()
        data = resp.json()
        results = []
        for r in data.get('organic_results', [])[:num_results]:
            results.append({
                'title': r.get('title', ''),
                'link': r.get('link', ''),
                'snippet': r.get('snippet', ''),
            })
        return results
    except Exception as e:
        print(f'Search error: {e}')
        return []

# Test the wrapper
results = web_search('latest python release 2026')
for r in results:
    print(f'{r["title"]}')
    print(f'  {r["link"]}')
    print(f'  {r["snippet"][:80]}')
print(f'Cost: $0.005 per search')

Step 3: Configure OpenWebUI to use the API

Update OpenWebUI environment variables to point to the new search backend.

Python
# Option 1: Set via environment variables in docker-compose.yml
# services:
#   open-webui:
#     environment:
#       - ENABLE_RAG_WEB_SEARCH=true
#       - RAG_WEB_SEARCH_ENGINE=custom
#       - SCAVIO_API_KEY=your_key_here

# Option 2: Create a custom search tool in OpenWebUI
# Navigate to: Settings > Tools > Add Tool
# Paste this as a tool function:

def openwebui_search_tool(query: str) -> str:
    """Search the web for current information."""
    import requests, os
    SH = {'x-api-key': os.environ.get('SCAVIO_API_KEY', ''),
           'Content-Type': 'application/json'}
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers=SH, json={'query': query, 'country_code': 'us', 'num_results': 5},
        timeout=10)
    data = resp.json()
    results = data.get('organic_results', [])
    formatted = []
    for r in results[:5]:
        formatted.append(f"Title: {r.get('title', '')}\nURL: {r.get('link', '')}\nSnippet: {r.get('snippet', '')}")
    return '\n\n'.join(formatted) if formatted else 'No results found.'

# Test the tool function
result = openwebui_search_tool('best search api 2026')
print(result)

Step 4: Verify search is working end to end

Run a batch test to confirm reliability across different query types.

Python
import time

def verify_search(queries):
    print('=== OpenWebUI Search Verification ===')
    successes = 0
    total_time = 0
    for q in queries:
        start = time.time()
        results = web_search(q)
        elapsed = time.time() - start
        total_time += elapsed
        status = 'OK' if results else 'FAIL'
        if results:
            successes += 1
        print(f'  [{status}] "{q}" -> {len(results)} results in {elapsed:.2f}s')
    print(f'\nSuccess rate: {successes}/{len(queries)} ({successes/len(queries)*100:.0f}%)')
    print(f'Avg latency: {total_time/len(queries):.2f}s')
    print(f'Total cost: ${len(queries) * 0.005:.3f}')

verify_search([
    'python asyncio tutorial',
    'react server components 2026',
    'kubernetes best practices',
    'machine learning framework comparison',
    'latest docker release notes',
])

Python Example

Python
import os, requests
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}

def web_search(query, n=5):
    data = requests.post('https://api.scavio.dev/api/v1/search',
        headers=SH, json={'query': query, 'country_code': 'us', 'num_results': n}).json()
    return [{'title': r['title'], 'link': r['link'], 'snippet': r.get('snippet', '')}
            for r in data.get('organic_results', [])[:n]]

for r in web_search('openwebui search fix 2026'):
    print(f'{r["title"]}: {r["link"]}')
print('Cost: $0.005')

JavaScript Example

JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function webSearch(query, n = 5) {
  const data = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST', headers: SH,
    body: JSON.stringify({ query, country_code: 'us', num_results: n })
  }).then(r => r.json());
  return (data.organic_results || []).slice(0, n);
}
const results = await webSearch('openwebui search fix 2026');
results.forEach(r => console.log(`${r.title}: ${r.link}`));

Expected Output

JSON
Status: 200
Results: 10
Latency: 0.45s
First result: Python Web Frameworks Guide 2026
API is working. Issue is in OpenWebUI search config.

=== OpenWebUI Search Verification ===
  [OK] "python asyncio tutorial" -> 5 results in 0.42s
  [OK] "react server components 2026" -> 5 results in 0.38s
  [OK] "kubernetes best practices" -> 5 results in 0.40s
  [OK] "machine learning framework comparison" -> 5 results in 0.39s
  [OK] "latest docker release notes" -> 5 results in 0.41s

Success rate: 5/5 (100%)
Avg latency: 0.40s
Total cost: $0.025

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.

OpenWebUI instance running. Python 3.8+. A Scavio API key from scavio.dev. Admin access to OpenWebUI config. 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 broken OpenWebUI web search with a reliable search API. Step-by-step fix for timeout and empty result errors.