Nebius acquired Tavily in February 2026, raising questions about pricing changes, data handling, and long-term availability. If you want to diversify away from Tavily or need multi-platform search beyond web results, Scavio provides Google, Amazon, YouTube, Walmart, Reddit, and TikTok from one endpoint. Tavily charges $30/month for 10K requests. Scavio charges $30/month for 7K credits at $0.005 each, but covers six platforms instead of just web search. This tutorial walks through the migration.
Prerequisites
- An existing Tavily integration to migrate
- Python 3.9+ installed
- A Scavio API key from scavio.dev
- requests library installed
Walkthrough
Step 1: Map Tavily API calls to Scavio equivalents
Tavily uses a search endpoint with topic and search_depth params. Scavio uses a POST endpoint with query and num_results. Map the key differences.
# Tavily API call (what you currently have)
# POST https://api.tavily.com/search
# Body: {"api_key": "tvly-...", "query": "...", "search_depth": "advanced",
# "topic": "general", "max_results": 5}
#
# Scavio API call (replacement)
# POST https://api.scavio.dev/api/v1/search
# Headers: {"x-api-key": "your-key"}
# Body: {"query": "...", "country_code": "us", "num_results": 5}
import os, requests
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def tavily_to_scavio_search(query: str, max_results: int = 5, **kwargs) -> dict:
"""Drop-in replacement for tavily.search()."""
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us', 'num_results': max_results})
resp.raise_for_status()
data = resp.json()
# Return Tavily-compatible response shape
return {
'query': query,
'results': [{'title': r['title'], 'url': r['link'],
'content': r.get('snippet', ''), 'score': 0.9 - (i * 0.05)}
for i, r in enumerate(data.get('organic_results', []))]
}
result = tavily_to_scavio_search('AI agent frameworks 2026')
print(f'Query: {result["query"]}')
for r in result['results']:
print(f' {r["title"][:60]} (score: {r["score"]:.2f})')Step 2: Replace the Tavily Python client
If you use the tavily-python package, create a compatible wrapper class that mimics TavilyClient. Your existing code calls the same methods but hits Scavio instead.
class ScavioSearchClient:
"""Drop-in replacement for TavilyClient."""
def __init__(self, api_key: str = None):
self.api_key = api_key or os.environ['SCAVIO_API_KEY']
self.base_url = 'https://api.scavio.dev/api/v1/search'
def search(self, query: str, max_results: int = 5, **kwargs) -> dict:
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': max_results})
resp.raise_for_status()
organic = resp.json().get('organic_results', [])
return {
'query': query,
'results': [{'title': r['title'], 'url': r['link'],
'content': r.get('snippet', ''), 'score': 0.9}
for r in organic]
}
def get_search_context(self, query: str, max_results: int = 5, **kwargs) -> str:
results = self.search(query, max_results)
return '\n\n'.join(f"{r['title']}\n{r['content']}\nSource: {r['url']}"
for r in results['results'])
# Replace: client = TavilyClient(api_key=TAVILY_KEY)
client = ScavioSearchClient()
context = client.get_search_context('latest Python release 2026')
print(context[:300])Step 3: Update LangChain integration
If you use TavilySearchResults in LangChain, swap it for a custom Scavio tool. The tool interface is identical so your chain or agent code stays the same.
from langchain_core.tools import tool
@tool
def search(query: str) -> str:
"""Search the web for current information. Returns titles, snippets, and URLs."""
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us', 'num_results': 5})
results = resp.json().get('organic_results', [])
return '\n\n'.join(
f"Title: {r['title']}\nSnippet: {r.get('snippet', '')}\nURL: {r['link']}"
for r in results
)
# BEFORE (Tavily):
# from langchain_community.tools.tavily_search import TavilySearchResults
# tools = [TavilySearchResults(max_results=5)]
# AFTER (Scavio):
tools = [search]
# Your agent code stays the same
print(f'Tool name: {tools[0].name}')
print(f'Tool description: {tools[0].description}')
result = tools[0].invoke('best AI frameworks 2026')
print(result[:200])Step 4: Validate the migration with test queries
Run your most common queries through both APIs and compare result quality. Check that titles, snippets, and URLs are populated.
def validate_migration(queries: list[str]):
client = ScavioSearchClient()
print('Tavily -> Scavio Migration Validation')
print('=' * 45)
all_pass = True
for q in queries:
result = client.search(q, max_results=5)
items = result.get('results', [])
has_results = len(items) > 0
has_content = all(r.get('content') for r in items[:3])
has_urls = all(r.get('url') for r in items)
status = 'PASS' if (has_results and has_urls) else 'FAIL'
if status == 'FAIL':
all_pass = False
print(f'\n[{status}] {q}')
print(f' Results: {len(items)}, Content: {has_content}, URLs: {has_urls}')
if items:
print(f' Top: {items[0]["title"][:50]}')
print(f'\nOverall: {"PASS" if all_pass else "SOME FAILURES"}')
print(f'\nPricing comparison:')
print(f' Tavily: $30/mo for 10K searches (web only)')
print(f' Scavio: $30/mo for 7K credits (6 platforms)')
validate_migration([
'latest AI news 2026',
'best python web framework',
'how to deploy on railway',
])Python Example
import os, requests
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
class ScavioSearchClient:
def __init__(self, api_key=None):
self.key = api_key or SCAVIO_KEY
def search(self, query, max_results=5):
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': self.key, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us', 'num_results': max_results})
return {'results': [{'title': r['title'], 'url': r['link'],
'content': r.get('snippet', '')} for r in resp.json().get('organic_results', [])]}
def get_search_context(self, query, max_results=5):
results = self.search(query, max_results)
return '\n'.join(f"{r['title']}: {r['content']}" for r in results['results'])
client = ScavioSearchClient()
print(client.get_search_context('AI frameworks 2026'))JavaScript Example
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
class ScavioSearchClient {
constructor(apiKey) { this.key = apiKey || SCAVIO_KEY; }
async search(query, maxResults = 5) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': this.key, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us', num_results: maxResults })
});
const data = await resp.json();
return { results: (data.organic_results || []).map(r => ({
title: r.title, url: r.link, content: r.snippet || ''
}))};
}
async getSearchContext(query, maxResults = 5) {
const { results } = await this.search(query, maxResults);
return results.map(r => `${r.title}: ${r.content}`).join('\n');
}
}
const client = new ScavioSearchClient();
client.getSearchContext('AI frameworks 2026').then(console.log);Expected Output
Tavily -> Scavio Migration Validation
=============================================
[PASS] latest AI news 2026
Results: 5, Content: True, URLs: True
Top: AI News Roundup: Top Developments in 2026
[PASS] best python web framework
Results: 5, Content: True, URLs: True
Overall: PASS
Pricing comparison:
Tavily: $30/mo for 10K searches (web only)
Scavio: $30/mo for 7K credits (6 platforms)