Tutorial

How to Track GEO Visibility with a Search API

Track brand citations across Google AI Overviews daily using a search API. Python pipeline with include_ai_overview param at $0.005/check.

Google AI Overviews now appear on over 30% of commercial queries, and brands cited in those overviews capture clicks without ranking in the traditional top 10. Tracking whether your brand appears in AI Overviews requires checking each target keyword with the include_ai_overview parameter and parsing the response for brand mentions. This tutorial builds a daily GEO visibility tracker at $0.005 per keyword check.

Prerequisites

  • Python 3.8+
  • requests library
  • A Scavio API key from scavio.dev
  • A list of target keywords to monitor

Walkthrough

Step 1: Set up the GEO tracking configuration

Define your brand terms and target keywords to monitor for AI Overview citations.

Python
import os, requests, json, sqlite3
from datetime import datetime

API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}

BRAND_TERMS = ['scavio', 'scavio.dev', 'scavio api']
KEYWORDS = ['best serp api 2026', 'search api for agents', 'google search api python',
            'web scraping alternative', 'ai agent search tool']

db = sqlite3.connect('geo_visibility.db')
db.execute('''CREATE TABLE IF NOT EXISTS checks (
    keyword TEXT, checked_at TEXT, has_ai_overview INTEGER,
    brand_cited INTEGER, citation_text TEXT, position INTEGER
)''')
db.commit()
print(f'Tracking {len(KEYWORDS)} keywords for {len(BRAND_TERMS)} brand terms')

Step 2: Check AI Overview presence and brand citations

Query each keyword with include_ai_overview and parse for brand mentions.

Python
def check_keyword(keyword, brand_terms):
    data = requests.post('https://api.scavio.dev/api/v1/search',
        headers=SH, json={'query': keyword, 'country_code': 'us',
                          'include_ai_overview': True}).json()
    ao = data.get('ai_overview', {})
    ao_text = json.dumps(ao).lower() if ao else ''
    cited = any(b in ao_text for b in brand_terms)
    org = data.get('organic_results', [])
    pos = next((r['position'] for r in org
                if any(b in r.get('link', '').lower() for b in brand_terms)), None)
    now = datetime.now().isoformat()
    db.execute('INSERT INTO checks VALUES (?,?,?,?,?,?)',
        (keyword, now, 1 if ao else 0, 1 if cited else 0,
         ao_text[:500] if cited else '', pos))
    db.commit()
    return {'keyword': keyword, 'has_ao': bool(ao), 'cited': cited, 'position': pos}

for kw in KEYWORDS:
    r = check_keyword(kw, BRAND_TERMS)
    status = 'CITED' if r['cited'] else ('AO present' if r['has_ao'] else 'No AO')
    print(f'  {kw:35} | {status:12} | Organic: #{r["position"] or "-"}')

Step 3: Generate a daily visibility report

Aggregate check results into a daily GEO visibility score.

Python
def daily_report():
    today = datetime.now().strftime('%Y-%m-%d')
    rows = db.execute(
        "SELECT keyword, has_ai_overview, brand_cited, position FROM checks WHERE checked_at LIKE ?",
        (f'{today}%',)).fetchall()
    total = len(rows)
    ao_count = sum(1 for r in rows if r[1])
    cited_count = sum(1 for r in rows if r[2])
    avg_pos = [r[3] for r in rows if r[3]]
    print(f'\nGEO Visibility Report - {today}')
    print(f'  Keywords checked: {total}')
    print(f'  AI Overviews present: {ao_count}/{total} ({ao_count/total*100:.0f}%)')
    print(f'  Brand cited in AO: {cited_count}/{total} ({cited_count/total*100:.0f}%)')
    if avg_pos:
        print(f'  Avg organic position: {sum(avg_pos)/len(avg_pos):.1f}')
    print(f'  Cost: ${total * 0.005:.3f}')
    return {'date': today, 'total': total, 'ao_rate': ao_count/total, 'citation_rate': cited_count/total}

daily_report()

Step 4: Track citation trends over time

Compare daily scores to detect GEO visibility gains or losses.

Python
def trend_report(days=7):
    rows = db.execute(
        'SELECT DATE(checked_at) as d, AVG(has_ai_overview), AVG(brand_cited) FROM checks GROUP BY d ORDER BY d DESC LIMIT ?',
        (days,)).fetchall()
    print(f'\nGEO Visibility Trend ({len(rows)} days):')
    for date, ao_rate, cite_rate in rows:
        bar_ao = '#' * int(ao_rate * 20)
        bar_cite = '#' * int(cite_rate * 20)
        print(f'  {date} | AO: {ao_rate*100:5.1f}% {bar_ao:20} | Cited: {cite_rate*100:5.1f}% {bar_cite:20}')
    if len(rows) >= 2:
        change = (rows[0][2] - rows[-1][2]) * 100
        direction = 'UP' if change > 0 else 'DOWN' if change < 0 else 'FLAT'
        print(f'  Citation rate {direction} {abs(change):.1f}pp over {len(rows)} days')

trend_report()

Python Example

Python
import os, requests, json
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}

def check_geo(keyword, brand):
    data = requests.post('https://api.scavio.dev/api/v1/search',
        headers=SH, json={'query': keyword, 'country_code': 'us', 'include_ai_overview': True}).json()
    ao = data.get('ai_overview', {})
    cited = brand.lower() in json.dumps(ao).lower() if ao else False
    print(f'{keyword}: AO={bool(ao)}, Brand cited={cited}. Cost: $0.005')

check_geo('best serp api 2026', 'scavio')

JavaScript Example

JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function checkGeo(keyword, brand) {
  const data = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST', headers: SH,
    body: JSON.stringify({ query: keyword, country_code: 'us', include_ai_overview: true })
  }).then(r => r.json());
  const ao = data.ai_overview || {};
  const cited = JSON.stringify(ao).toLowerCase().includes(brand.toLowerCase());
  console.log(`${keyword}: AO=${!!data.ai_overview}, Cited=${cited}`);
}
checkGeo('best serp api 2026', 'scavio').catch(console.error);

Expected Output

JSON
Tracking 5 keywords for 3 brand terms
  best serp api 2026                  | CITED        | Organic: #4
  search api for agents               | AO present   | Organic: #6
  google search api python            | No AO        | Organic: #8
  web scraping alternative            | AO present   | Organic: #12
  ai agent search tool                | CITED        | Organic: #5

GEO Visibility Report - 2026-05-19
  Keywords checked: 5
  AI Overviews present: 4/5 (80%)
  Brand cited in AO: 2/5 (40%)
  Avg organic position: 7.0
  Cost: $0.025

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.

Python 3.8+. requests library. A Scavio API key from scavio.dev. A list of target keywords to monitor. 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

Track brand citations across Google AI Overviews daily using a search API. Python pipeline with include_ai_overview param at $0.005/check.