Tutorial

How to Add a Search API to OpenWebUI

Replace Tavily in OpenWebUI with a multi-platform search API. Step-by-step setup for web search grounding in OpenWebUI using Scavio.

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.

Python
# 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/v1/search'

    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={'x-api-key': self.api_key,
                         'Content-Type': 'application/json'},
                json={'query': query, 'country_code': 'us',
                      'num_results': num_results or 5},
                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.

Python
# 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/v1/search'
        self.headers = {'x-api-key': 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, 'country_code': 'us', 'num_results': num}, 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.

Python
# 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.

Python
# 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 (250 free/month)')

Python Example

Python
import os, requests

class ScavioOpenWebUI:
    def __init__(self):
        self.key = os.environ.get('SCAVIO_API_KEY', '')
        self.url = 'https://api.scavio.dev/api/v1/search'
        self.h = {'x-api-key': self.key, 'Content-Type': 'application/json'}
    def search(self, query, num=5):
        resp = requests.post(self.url, headers=self.h,
            json={'query': query, 'country_code': 'us', 'num_results': num})
        return resp.json().get('organic_results', [])
    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

JavaScript
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('https://api.scavio.dev/api/v1/search', {
    method: 'POST',
    headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ query: q, country_code: 'us', num_results: 5 })
  });
  const results = (await resp.json()).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

JSON
[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 (250 free/month)

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 installed and running. A Scavio API key from scavio.dev. Python 3.9+ for the custom function approach. Admin access to your OpenWebUI instance. 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 Tavily in OpenWebUI with a multi-platform search API. Step-by-step setup for web search grounding in OpenWebUI using Scavio.