Tutorial

How to Monitor Search Surfaces Beyond Rank

Track AI Overviews, PAA, featured snippets, and local packs alongside rank. Python monitoring pipeline.

A page ranking #1 can get zero clicks if an AI Overview answers the query above it. Search surface monitoring tracks every SERP feature: AI Overviews, PAA boxes, snippets, knowledge panels, and local packs. When features change, your visibility changes even if rank stays the same. This tutorial builds a surface monitor at $0.005/keyword.

Prerequisites

  • Python 3.8+
  • requests library
  • A Scavio API key from scavio.dev
  • Keywords to monitor

Walkthrough

Step 1: Capture full SERP surfaces

Parse all feature types for each keyword.

Python
import os, requests, json
from datetime import date

API_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
DOMAIN = 'mysite.com'
KEYWORDS = ['serp api python', 'web scraping api 2026', 'tiktok data api']

def capture(keyword):
    data = requests.post('https://api.scavio.dev/api/v1/search',
        headers=H, json={'query': keyword, 'country_code': 'us'}).json()
    features = {}
    if data.get('answer_box'): features['answer_box'] = True
    if data.get('ai_overview'): features['ai_overview'] = True
    if data.get('related_questions'): features['paa'] = len(data['related_questions'])
    if data.get('knowledge_graph'): features['kg'] = True
    pos = next((r['position'] for r in data.get('organic_results', []) if DOMAIN in r.get('link', '')), None)
    return {'keyword': keyword, 'date': date.today().isoformat(), 'features': features, 'position': pos}

Step 2: Compare against previous snapshots

Detect when features appear or disappear.

Python
def detect_changes(current, previous):
    if not previous: return ['NEW: first capture']
    changes = []
    curr_f = set(current['features'])
    prev_f = set(previous.get('features', {}))
    for f in curr_f - prev_f: changes.append(f'ADDED: {f}')
    for f in prev_f - curr_f: changes.append(f'REMOVED: {f}')
    cp, pp = current.get('position'), previous.get('position')
    if cp and pp and cp != pp: changes.append(f'RANK: {pp} -> {cp}')
    return changes

Step 3: Run the monitor

Capture, compare, and save state.

Python
def run_monitor():
    try:
        with open('surface.json') as f: prev = {e['keyword']: e for line in f for e in [json.loads(line)]}
    except FileNotFoundError: prev = {}
    surfaces = []
    for kw in KEYWORDS:
        s = capture(kw)
        surfaces.append(s)
        changes = detect_changes(s, prev.get(kw))
        feats = ', '.join(s['features']) or 'organic only'
        print(f'  {kw}: pos={s["position"] or "N/A"}, [{feats}]')
        for c in changes: print(f'    {c}')
    with open('surface.json', 'w') as f:
        for s in surfaces: f.write(json.dumps(s) + '\n')
    print(f'Cost: ${len(KEYWORDS) * 0.005:.3f}')

run_monitor()

Step 4: Calculate visibility score

Estimate CTR impact from SERP features.

Python
def visibility(surface):
    pos = surface.get('position')
    if not pos: return 0.0
    base = {1: 0.30, 2: 0.15, 3: 0.10, 4: 0.07, 5: 0.05}.get(pos, 0.02)
    if 'ai_overview' in surface.get('features', {}): base *= 0.5
    if 'answer_box' in surface.get('features', {}): base *= 0.7
    return round(base, 4)

for kw in KEYWORDS:
    s = capture(kw)
    v = visibility(s)
    print(f'  {kw}: pos={s["position"]}, visibility={v:.2%}')

Python Example

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

def check(kw, domain):
    data = requests.post('https://api.scavio.dev/api/v1/search',
        headers=H, json={'query': kw, 'country_code': 'us'}).json()
    features = [k for k in ['answer_box', 'ai_overview', 'related_questions', 'knowledge_graph'] if data.get(k)]
    pos = next((r['position'] for r in data.get('organic_results', []) if domain in r.get('link', '')), None)
    print(f'{kw}: pos={pos or "N/A"}, features={features}')

check('serp api python', 'mysite.com')

JavaScript Example

JavaScript
const API_KEY = process.env.SCAVIO_API_KEY;
const H = { 'x-api-key': API_KEY, 'Content-Type': 'application/json' };
async function check(kw, domain) {
  const data = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST', headers: H, body: JSON.stringify({ query: kw, country_code: 'us' })
  }).then(r => r.json());
  const features = ['answer_box', 'ai_overview', 'related_questions'].filter(k => data[k]);
  const match = (data.organic_results || []).find(r => r.link.includes(domain));
  console.log(`${kw}: pos=${match?.position||'N/A'}, features=[${features}]`);
}
check('serp api python', 'mysite.com').catch(console.error);

Expected Output

JSON
  serp api python: pos=4, [paa]
  web scraping api 2026: pos=7, [ai_overview, paa, answer_box]
    ADDED: ai_overview
    RANK: 5 -> 7
  tiktok data api: pos=2, [paa]
Cost: $0.015

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. 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 AI Overviews, PAA, featured snippets, and local packs alongside rank. Python monitoring pipeline.