Tutorial

How to Track AI Overview Citations with SERP API

Monitor which queries cite your brand in Google AI Overviews. Use include_ai_overview to track citation presence, source ranking, and coverage gaps.

Google AI Overviews now appear for over 40% of informational queries in 2026. Being cited in an AI Overview drives significant click-through even when your page is not in the top 3 organic results. Tracking which queries cite your domain and which do not is the new ranking report. This tutorial builds a citation tracker that checks a list of target queries, records whether your domain appears in the AI Overview sources, and logs results over time for trend analysis. Each check costs one Scavio API credit at $0.005.

Prerequisites

  • Python 3.9+ installed
  • requests library installed
  • A Scavio API key from scavio.dev
  • A list of target queries relevant to your domain

Walkthrough

Step 1: Define target queries and domain

Set up a list of queries you want to track for AI Overview citations. These should be informational queries where you expect your content to be relevant.

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

SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}
URL = 'https://api.scavio.dev/api/v1/search'

TARGET_DOMAIN = 'scavio.dev'
QUERIES = [
    'best search api for developers',
    'how to get google search results programmatically',
    'serp api comparison 2026',
    'web search api for ai agents',
    'mcp search server',
]

Step 2: Check AI Overview citation for a single query

Search with include_ai_overview enabled and check if the target domain appears in the AI Overview sources list.

Python
def check_citation(query: str, domain: str) -> dict:
    resp = requests.post(URL, headers=H,
        json={'query': query, 'country_code': 'us', 'include_ai_overview': True})
    data = resp.json()
    ai = data.get('ai_overview', {})
    sources = ai.get('sources', [])
    cited = False
    citation_position = None
    for i, src in enumerate(sources):
        if domain in src.get('link', ''):
            cited = True
            citation_position = i + 1
            break
    organic = data.get('organic_results', [])
    organic_pos = None
    for r in organic:
        if domain in r.get('link', ''):
            organic_pos = r.get('position')
            break
    return {
        'query': query,
        'ai_overview_present': bool(ai.get('text')),
        'cited': cited,
        'citation_position': citation_position,
        'organic_position': organic_pos,
        'total_ai_sources': len(sources),
        'timestamp': datetime.now().isoformat(),
    }

Step 3: Batch check all queries and save results

Iterate through all target queries, check citations, and save the results to a JSON file for historical tracking.

Python
def track_citations(queries: list, domain: str) -> list:
    results = []
    for q in queries:
        result = check_citation(q, domain)
        results.append(result)
        status = 'CITED' if result['cited'] else 'MISSING'
        print(f'[{status}] "{q}" | AI src #{result["citation_position"]} | Organic #{result["organic_position"]}')
        time.sleep(0.5)
    # Save snapshot
    snapshot = {'date': datetime.now().strftime('%Y-%m-%d'), 'domain': domain, 'results': results}
    filename = f'ai_citations_{snapshot["date"]}.json'
    with open(filename, 'w') as f:
        json.dump(snapshot, f, indent=2)
    cited_count = sum(1 for r in results if r['cited'])
    print(f'\nCitation rate: {cited_count}/{len(results)} ({cited_count/len(results)*100:.0f}%)')
    print(f'Saved to {filename}')
    return results

results = track_citations(QUERIES, TARGET_DOMAIN)

Step 4: Compare citations over time

Load previous snapshots and compare citation status to detect gains and losses in AI Overview visibility.

Python
def compare_snapshots(current_file: str, previous_file: str):
    with open(current_file) as f:
        current = json.load(f)
    with open(previous_file) as f:
        previous = json.load(f)
    prev_map = {r['query']: r['cited'] for r in previous['results']}
    print(f'Citation changes: {previous["date"]} -> {current["date"]}')
    for r in current['results']:
        was_cited = prev_map.get(r['query'], False)
        is_cited = r['cited']
        if is_cited and not was_cited:
            print(f'  [GAINED] {r["query"]}')
        elif not is_cited and was_cited:
            print(f'  [LOST]   {r["query"]}')
        elif is_cited:
            print(f'  [KEPT]   {r["query"]}')

# compare_snapshots('ai_citations_2026-05-16.json', 'ai_citations_2026-05-09.json')

Python Example

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

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

def check_ai_citation(query, domain):
    resp = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
        json={'query': query, 'country_code': 'us', 'include_ai_overview': True})
    data = resp.json()
    sources = data.get('ai_overview', {}).get('sources', [])
    cited = any(domain in s.get('link', '') for s in sources)
    pos = next((i+1 for i, s in enumerate(sources) if domain in s.get('link', '')), None)
    return {'query': query, 'cited': cited, 'position': pos}

queries = ['search api for developers', 'serp api python', 'web search mcp server']
for q in queries:
    r = check_ai_citation(q, 'scavio.dev')
    print(f'[{"CITED" if r["cited"] else "MISS"}] {q} (pos: {r["position"]})')
    time.sleep(0.5)

JavaScript Example

JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;

async function checkAICitation(query, domain) {
  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, country_code: 'us', include_ai_overview: true })
  });
  const data = await resp.json();
  const sources = data.ai_overview?.sources || [];
  const cited = sources.some(s => (s.link || '').includes(domain));
  const pos = sources.findIndex(s => (s.link || '').includes(domain)) + 1 || null;
  console.log(`[${cited ? 'CITED' : 'MISS'}] ${query} (pos: ${pos})`);
}

const queries = ['search api for developers', 'serp api python'];
(async () => { for (const q of queries) await checkAICitation(q, 'scavio.dev'); })();

Expected Output

JSON
[CITED] "best search api for developers" | AI src #2 | Organic #4
[MISSING] "how to get google search results programmatically" | AI src #None | Organic #7
[CITED] "serp api comparison 2026" | AI src #1 | Organic #3
[MISSING] "web search api for ai agents" | AI src #None | Organic #12
[CITED] "mcp search server" | AI src #3 | Organic #2

Citation rate: 3/5 (60%)
Saved to ai_citations_2026-05-16.json

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.9+ installed. requests library installed. A Scavio API key from scavio.dev. A list of target queries relevant to your domain. 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

Monitor which queries cite your brand in Google AI Overviews. Use include_ai_overview to track citation presence, source ranking, and coverage gaps.