OpenSEO is an open-source SEO toolkit that needs a SERP data source. Most users connect expensive providers like DataForSEO ($50 minimum) or SerpAPI ($25/mo). This tutorial connects Scavio as the data source at $0.005/query with no minimum spend. You get the same rank tracking, keyword analysis, and SERP features data at a fraction of the cost.
Prerequisites
- Python 3.8+
- requests library
- A Scavio API key from scavio.dev
- OpenSEO installed or any SEO dashboard
Walkthrough
Step 1: Build the Scavio data adapter for OpenSEO
Create an adapter that translates Scavio API responses into the format OpenSEO expects.
import os, requests, json
from datetime import datetime
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
def scavio_serp(keyword, country='us'):
"""Fetch SERP data in OpenSEO-compatible format."""
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': country}, timeout=10).json()
organic = []
for i, r in enumerate(data.get('organic_results', [])):
organic.append({
'position': i + 1,
'title': r.get('title', ''),
'url': r.get('link', ''),
'domain': r.get('displayed_link', '').split('/')[0] if r.get('displayed_link') else '',
'snippet': r.get('snippet', ''),
})
paa = [q.get('question', '') for q in data.get('people_also_ask', [])]
featured = data.get('featured_snippet', {})
return {
'keyword': keyword,
'country': country,
'timestamp': datetime.now().isoformat(),
'organic_results': organic,
'people_also_ask': paa,
'has_featured_snippet': bool(featured),
'featured_snippet_domain': featured.get('displayed_link', ''),
'total_results': len(organic),
}
# Test
result = scavio_serp('best search api 2026')
print(f'Keyword: {result["keyword"]}')
print(f'Results: {result["total_results"]}')
print(f'PAA questions: {len(result["people_also_ask"])}')
for r in result['organic_results'][:3]:
print(f' #{r["position"]} {r["domain"]:25} {r["title"][:40]}')Step 2: Batch keyword tracking for OpenSEO
Track multiple keywords and output data in the format OpenSEO dashboards consume.
def batch_track(keywords, domain, country='us'):
"""Track ranking positions for a domain across multiple keywords."""
results = []
for kw in keywords:
serp = scavio_serp(kw, country)
position = None
for r in serp['organic_results']:
if domain.lower() in r['url'].lower():
position = r['position']
break
results.append({
'keyword': kw,
'position': position,
'in_featured': serp['has_featured_snippet'] and domain in serp.get('featured_snippet_domain', ''),
'total_results': serp['total_results'],
'timestamp': serp['timestamp'],
})
status = f'#{position}' if position else 'not found'
print(f' {kw[:40]:40} | {status:10}')
ranked = sum(1 for r in results if r['position'])
avg_pos = sum(r['position'] for r in results if r['position']) / ranked if ranked else 0
print(f'\nSummary: {ranked}/{len(keywords)} ranked | Avg position: {avg_pos:.1f}')
print(f'Cost: ${len(keywords) * 0.005:.3f}')
return results
keywords = ['search api python', 'serp api pricing', 'mcp search tool', 'web search api free']
tracking = batch_track(keywords, 'scavio.dev')Step 3: Export data for OpenSEO import
Save tracking data in CSV and JSON formats that OpenSEO can ingest.
import csv
def export_for_openseo(results, domain):
# JSON export
json_file = f'openseo_tracking_{datetime.now().strftime("%Y%m%d")}.json'
with open(json_file, 'w') as f:
json.dump({'domain': domain, 'date': datetime.now().strftime('%Y-%m-%d'),
'keywords': results}, f, indent=2)
print(f' JSON: {json_file}')
# CSV export
csv_file = f'openseo_tracking_{datetime.now().strftime("%Y%m%d")}.csv'
with open(csv_file, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['keyword', 'position', 'in_featured', 'timestamp'])
writer.writeheader()
for r in results:
writer.writerow({k: r[k] for k in ['keyword', 'position', 'in_featured', 'timestamp']})
print(f' CSV: {csv_file}')
print(f'\n Import into OpenSEO:')
print(f' 1. Go to OpenSEO > Data Sources > Import')
print(f' 2. Upload {json_file} or {csv_file}')
print(f' 3. Map fields: keyword, position, timestamp')
print(f'\n DataForSEO: $50 minimum, $0.002/query')
print(f' SerpAPI: $25/mo for 1K queries')
print(f' Scavio: No minimum, $0.005/query, 250 free/mo')
export_for_openseo(tracking, 'scavio.dev')Python Example
import os, requests
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def track_keyword(keyword, domain):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': keyword, 'country_code': 'us'}, timeout=10).json()
pos = next((i+1 for i, r in enumerate(data.get('organic_results', [])) if domain in r.get('link', '')), None)
print(f'{keyword[:35]:35} | Position: {pos or "not found"}')
track_keyword('search api python', 'scavio.dev')JavaScript Example
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query: 'search api python', country_code: 'us' })
}).then(r => r.json());
const pos = (data.organic_results || []).findIndex(r => r.link?.includes('scavio.dev'));
console.log(`Position: ${pos >= 0 ? pos + 1 : 'not found'}`);Expected Output
Keyword: best search api 2026
Results: 10
PAA questions: 4
#1 scavio.dev Best Search API for AI Agents - Scavio
#2 tavily.com Tavily Search API - AI-Optimized Search
#3 serpapi.com SerpAPI - Google Search API
search api python | #3
serp api pricing | #5
mcp search tool | #2
web search api free | #4
Summary: 4/4 ranked | Avg position: 3.5
Cost: $0.020
JSON: openseo_tracking_20260521.json
CSV: openseo_tracking_20260521.csv