OpenWebUI supports web search through Tavily, SearXNG, and custom endpoints. After Nebius acquired Tavily in February 2026, many users want an alternative. Scavio provides a compatible search endpoint that covers Google, Amazon, YouTube, Walmart, Reddit, and TikTok. This tutorial shows how to configure OpenWebUI to use Scavio for web search grounding, either through the built-in search settings or via a custom function tool.
Prerequisites
- OpenWebUI installed and running
- A Scavio API key from scavio.dev
- Python 3.9+ for the custom function approach
- Admin access to your OpenWebUI instance
Walkthrough
Step 1: Create a Scavio search function for OpenWebUI
OpenWebUI supports custom Python functions as tools. Create a search function that calls the Scavio API and returns formatted results the LLM can use.
# OpenWebUI Function Tool: scavio_search.py
# Add this as a Function in OpenWebUI Admin > Functions
import os
import requests
from typing import Optional
class Tools:
def __init__(self):
self.api_key = os.environ.get('SCAVIO_API_KEY', '')
self.base_url = 'https://api.scavio.dev/api/v2/google'
def search_web(self, query: str, num_results: Optional[int] = 5) -> str:
"""Search the web for current information using Scavio.
Returns titles, snippets, and source URLs.
"""
try:
resp = requests.post(self.base_url,
headers={'Authorization': 'Bearer ' + self.api_key,
'Content-Type': 'application/json'},
json={'query': query,
'gl': 'us'},
timeout=10)
resp.raise_for_status()
results = resp.json().get('organic_results', [])
if not results:
return 'No results found.'
return '\n\n'.join(
f'[{i+1}] {r["title"]}\n{r.get("snippet", "")}\nSource: {r["link"]}'
for i, r in enumerate(results)
)
except Exception as e:
return f'Search error: {str(e)}'Step 2: Add platform-specific search tools
Extend the function with tools for Reddit, YouTube, and Amazon search. OpenWebUI will show each as a separate tool the LLM can call.
# Extended Tools class with platform-specific methods
class Tools:
def __init__(self):
self.api_key = os.environ.get('SCAVIO_API_KEY', '')
self.base_url = 'https://api.scavio.dev/api/v2/google'
self.headers = {'Authorization': 'Bearer ' + self.api_key, 'Content-Type': 'application/json'}
def _search(self, query: str, num: int = 5) -> list:
resp = requests.post(self.base_url, headers=self.headers,
json={'query': query}, timeout=10)
resp.raise_for_status()
return resp.json().get('organic_results', [])
def search_web(self, query: str) -> str:
"""Search the web for current information."""
results = self._search(query)
return '\n\n'.join(f'[{i+1}] {r["title"]}\n{r.get("snippet","")}\nURL: {r["link"]}'
for i, r in enumerate(results)) or 'No results.'
def search_reddit(self, query: str) -> str:
"""Search Reddit for community discussions and opinions."""
results = self._search(f'site:reddit.com {query}')
return '\n\n'.join(f'[{i+1}] {r["title"]}\n{r.get("snippet","")}\nURL: {r["link"]}'
for i, r in enumerate(results)) or 'No Reddit results.'
def search_youtube(self, query: str) -> str:
"""Search YouTube for videos on a topic."""
results = self._search(f'site:youtube.com {query}')
return '\n\n'.join(f'[{i+1}] {r["title"]}\nURL: {r["link"]}'
for i, r in enumerate(results)) or 'No YouTube results.'
def search_amazon(self, query: str) -> str:
"""Search Amazon for product information."""
results = self._search(f'site:amazon.com {query}')
return '\n\n'.join(f'[{i+1}] {r["title"]}\n{r.get("snippet","")}\nURL: {r["link"]}'
for i, r in enumerate(results)) or 'No Amazon results.'Step 3: Configure the environment and deploy
Set the SCAVIO_API_KEY environment variable in your OpenWebUI deployment and add the function through the admin panel.
# Docker deployment: add to your docker-compose.yml or .env
# SCAVIO_API_KEY=your_key_here
# Or set in the OpenWebUI admin panel:
# 1. Go to Admin Panel > Functions
# 2. Click 'Create Function'
# 3. Paste the Tools class code
# 4. Set the function name to 'scavio_search'
# 5. Enable it globally or per-model
# Verify the setup with a test
import os, requests
def verify_openwebui_search():
key = os.environ.get('SCAVIO_API_KEY')
if not key:
print('ERROR: SCAVIO_API_KEY not set')
return False
tools = Tools()
result = tools.search_web('test query 2026')
if 'error' in result.lower():
print(f'ERROR: {result}')
return False
print('OpenWebUI search configured successfully')
print(f'Test result preview: {result[:150]}')
return True
verify_openwebui_search()Step 4: Test multi-platform queries in OpenWebUI
Verify that each platform search works correctly by running test queries. The LLM should automatically choose the right search tool based on the user question.
# Test all search functions
def test_all_tools():
tools = Tools()
tests = [
('search_web', 'latest AI news 2026'),
('search_reddit', 'best mechanical keyboard'),
('search_youtube', 'python tutorial beginners'),
('search_amazon', 'noise cancelling headphones'),
]
for method_name, query in tests:
method = getattr(tools, method_name)
result = method(query)
lines = result.split('\n')
has_results = len(lines) > 1
print(f'[{"PASS" if has_results else "FAIL"}] {method_name}')
print(f' Query: {query}')
print(f' First result: {lines[0][:60]}')
print()
test_all_tools()
print('All tools ready for OpenWebUI')
print('Cost: $0.005 per search (50 free credits on signup)')Python Example
import os, requests
class ScavioOpenWebUI:
def __init__(self):
self.key = os.environ.get('SCAVIO_API_KEY', '')
self.url = 'https://api.scavio.dev/api/v2/google'
self.h = {'Authorization': 'Bearer ' + self.key, 'Content-Type': 'application/json'}
def search(self, query, num=5):
resp = requests.post(self.url, headers=self.h,
json={'query': query, 'gl': 'us'})
return resp.json().get('organic_results', [])[:num]
def search_web(self, query):
results = self.search(query)
return '\n'.join(f'[{i+1}] {r["title"]}: {r.get("snippet","")}' for i, r in enumerate(results))
def search_reddit(self, query):
return self.search_web(f'site:reddit.com {query}')
tools = ScavioOpenWebUI()
print(tools.search_web('AI news 2026'))JavaScript Example
// Scavio has one endpoint per platform - there is no dispatcher endpoint and no
// `platform` request param, so the selector lives in your code.
const SCAVIO = "https://api.scavio.dev";
const SCAVIO_ENDPOINTS = {
google: "/api/v2/google",
reddit: "/api/v1/reddit/search",
youtube: "/api/v1/youtube/search",
amazon: "/api/v1/amazon/search",
walmart: "/api/v1/walmart/search",
};
const SCAVIO_QUERY_KEY = { youtube: "search" };
const SCAVIO_RESULTS_KEY = { google: "organic_results", reddit: "results",
youtube: "results", amazon: "products", walmart: "products" };
const scavioUrl = (platform) => SCAVIO + SCAVIO_ENDPOINTS[platform || "google"];
const scavioBody = (platform, query) =>
({ [SCAVIO_QUERY_KEY[platform || "google"] || "query"]: query });
// Google v2 passes Google's response through as-is; every other endpoint wraps
// its payload in `data`. Item fields differ per platform (see
// https://scavio.dev/docs), so only the result list is normalised here.
function scavioPayload(json, platform = "google") {
const p = platform || "google";
const out = p === "google" ? json : json.data;
return { ...out, results: out[SCAVIO_RESULTS_KEY[p]] || [] };
}
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
async function searchForOpenWebUI(query, platform = 'web') {
const prefixes = { reddit: 'site:reddit.com ', youtube: 'site:youtube.com ', amazon: 'site:amazon.com ' };
const q = (prefixes[platform] || '') + query;
const resp = await fetch(scavioUrl("google"), {
method: 'POST',
headers: { 'Authorization': `Bearer ${SCAVIO_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify(scavioBody("google", q))
});
const results = (scavioPayload(await resp.json(), "google")).organic_results || [];
return results.map((r, i) => `[${i+1}] ${r.title}\n${r.snippet || ''}\n${r.link}`).join('\n\n');
}
searchForOpenWebUI('AI agent tools 2026').then(console.log);Expected Output
[PASS] search_web
Query: latest AI news 2026
First result: [1] AI News: Latest Developments in Artificial
[PASS] search_reddit
Query: best mechanical keyboard
First result: [1] r/MechanicalKeyboards - Best keyboards mid-2
[PASS] search_youtube
Query: python tutorial beginners
First result: [1] Python Tutorial for Beginners - Full Course
[PASS] search_amazon
Query: noise cancelling headphones
First result: [1] Sony WH-1000XM6 Wireless Noise Cancelling
All tools ready for OpenWebUI
Cost: $0.005 per search (50 free credits on signup)