You can connect OpenWebUI to the Scavio search API by creating a custom Function tool in OpenWebUI's function editor. This replaces the default SearXNG integration with a reliable API-backed search that covers Google, Reddit, YouTube, and Amazon.
Prerequisites
- OpenWebUI installed (v0.4+)
- Scavio API key
- Admin access to OpenWebUI
Walkthrough
Step 1: Open the Function editor in OpenWebUI
Go to Workspace > Functions > New Function. Select Tool as the function type.
# Navigate to:
# Settings > Workspace > Functions > + (Add Function)
# Function Type: Tool
# Name: web_search
# Description: Search the web using ScavioStep 2: Write the function tool code
Paste this Python function into the OpenWebUI function editor. It calls the Scavio API and returns formatted results.
import requests
from pydantic import BaseModel, Field
# Scavio has one endpoint per platform -- there is no dispatcher endpoint and no
# "platform" request param, so the selector lives in this function.
ENDPOINTS = {
"google": ("/api/v2/google", "query"),
"reddit": ("/api/v1/reddit/search", "query"),
"youtube": ("/api/v1/youtube/search", "search"),
"amazon": ("/api/v1/amazon/search", "query"),
}
RESULT_KEYS = ("organic_results", "results", "products")
class Tools:
class Valves(BaseModel):
SCAVIO_API_KEY: str = Field(default="", description="Your Scavio API key")
def __init__(self):
self.valves = self.Valves()
def web_search(
self,
query: str,
platform: str = "google"
) -> str:
"""
Search the web for current information.
:param query: The search query
:param platform: Platform to search: google, reddit, youtube, amazon
:return: Formatted search results
"""
path, query_key = ENDPOINTS.get(platform, ENDPOINTS["google"])
try:
r = requests.post(
"https://api.scavio.dev" + path,
json={query_key: query},
headers={
"Authorization": f"Bearer {self.valves.SCAVIO_API_KEY}",
"Content-Type": "application/json",
},
timeout=15
)
r.raise_for_status()
payload = r.json()
# Google v2 passes Google's response through as-is; the other
# endpoints wrap their payload in a "data" object.
body = payload.get("data", payload)
results = next((body[k] for k in RESULT_KEYS if body.get(k)), [])
if not results:
return "No results found."
lines = []
for i, res in enumerate(results[:5], 1):
title = res.get("title") or res.get("name", "")
link = res.get("link") or res.get("url", "")
snippet = res.get("snippet") or res.get("text", "")
lines.append(f"{i}. {title}\n {snippet}\n {link}")
return "\n\n".join(lines)
except Exception as e:
return f"Search error: {str(e)}"Step 3: Configure the API key in Valve settings
After saving the function, click the Valve icon on the function card and enter your Scavio API key in SCAVIO_API_KEY.
# In OpenWebUI:
# Functions > web_search > Valve Settings (wrench icon)
# SCAVIO_API_KEY: your-scavio-api-key
# SaveStep 4: Enable the tool in a model chat
Start a new chat, click the tools icon, and enable 'web_search'. Test it with a query that requires current data.
# Test prompt:
# "What are the latest AI model releases in 2026? Search the web and summarize."
# Expected behavior:
# OpenWebUI calls web_search(query="latest AI model releases 2026")
# Returns top 5 results formatted as numbered list
# Model synthesizes the results into an answerPython Example
# Standalone test of the function logic before loading into OpenWebUI
import requests
SCAVIO_KEY = "your-scavio-api-key"
# One endpoint per platform -- Scavio has no dispatcher endpoint and no
# "platform" request param.
ENDPOINTS = {
"google": ("/api/v2/google", "query"),
"reddit": ("/api/v1/reddit/search", "query"),
"youtube": ("/api/v1/youtube/search", "search"),
"amazon": ("/api/v1/amazon/search", "query"),
}
RESULT_KEYS = ("organic_results", "results", "products")
def web_search(query: str, platform: str = "google", num_results: int = 5) -> str:
path, query_key = ENDPOINTS.get(platform, ENDPOINTS["google"])
try:
r = requests.post(
"https://api.scavio.dev" + path,
json={query_key: query},
headers={
"Authorization": f"Bearer {SCAVIO_KEY}",
"Content-Type": "application/json",
},
timeout=15
)
r.raise_for_status()
payload = r.json()
# Google v2 is a raw passthrough; the rest wrap their payload in "data".
body = payload.get("data", payload)
results = next((body[k] for k in RESULT_KEYS if body.get(k)), [])
if not results:
return "No results found."
lines = []
for i, res in enumerate(results[:num_results], 1):
title = res.get("title") or res.get("name", "")
link = res.get("link") or res.get("url", "")
snippet = res.get("snippet") or res.get("text", "")
lines.append(f"{i}. {title}\n {snippet}\n {link}")
return "\n\n".join(lines)
except Exception as e:
return f"Search error: {str(e)}"
# Test before deploying to OpenWebUI
if __name__ == "__main__":
print(web_search("latest AI models 2026"))
print("\n" + "="*50 + "\n")
print(web_search("Claude API pricing", platform="reddit"))JavaScript Example
// Test the API call from Node.js before configuring in OpenWebUI
const SCAVIO_KEY = 'your-scavio-api-key';
// One endpoint per platform -- Scavio has no dispatcher endpoint and no
// "platform" request param.
const ENDPOINTS = {
google: ['/api/v2/google', 'query'],
reddit: ['/api/v1/reddit/search', 'query'],
youtube: ['/api/v1/youtube/search', 'search'],
amazon: ['/api/v1/amazon/search', 'query'],
};
const RESULT_KEYS = ['organic_results', 'results', 'products'];
async function webSearch(query, platform = 'google', numResults = 5) {
const [path, queryKey] = ENDPOINTS[platform] ?? ENDPOINTS.google;
const res = await fetch('https://api.scavio.dev' + path, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${SCAVIO_KEY}`,
},
body: JSON.stringify({ [queryKey]: query })
});
if (!res.ok) return `Search error: HTTP ${res.status}`;
const payload = await res.json();
// Google v2 is a raw passthrough; the rest wrap their payload in "data".
const body = payload.data ?? payload;
const results = RESULT_KEYS.map(k => body[k]).find(v => v?.length) ?? [];
if (!results.length) return 'No results found.';
return results.slice(0, numResults).map((r, i) =>
`${i + 1}. ${r.title ?? r.name ?? ''}\n ${r.snippet ?? r.text ?? ''}\n ${r.link ?? r.url ?? ''}`
).join('\n\n');
}
console.log(await webSearch('latest AI models 2026'));Expected Output
1. Anthropic Releases Claude 4 Opus with Extended Thinking
Anthropic's latest model Claude 4 Opus introduces extended thinking mode and 200K context window...
https://anthropic.com/news/claude-4-opus
2. OpenAI GPT-5 Benchmark Results 2026
GPT-5 achieves state-of-the-art results on...
https://openai.com/research/gpt-5