Tutorial

How to Build a Competitor SERP Tracker

Learn how to build an automated SERP tracker that monitors competitor rankings daily and alerts you to position changes.

Tracking competitor search rankings manually is unsustainable. This tutorial builds an automated tracker that queries target keywords daily via Scavio's Google endpoint, logs competitor positions, and flags significant ranking changes. It costs a fraction of enterprise SERP tools because you pay per query with credit-based pricing instead of flat monthly fees.

Prerequisites

  • Python 3.8+ installed
  • requests library installed
  • A Scavio API key from scavio.dev
  • A list of target keywords and competitor domains

Walkthrough

Step 1: Define keywords and competitors

Set up your tracking configuration with target keywords and competitor domains.

Python
import os

API_KEY = os.environ['SCAVIO_API_KEY']
KEYWORDS = ['best crm 2026', 'project management software', 'invoice tool small business']
COMPETITORS = ['competitor1.com', 'competitor2.com', 'competitor3.com']
MY_DOMAIN = 'mydomain.com'

Step 2: Query rankings for each keyword

Search each keyword and extract positions for your domain and competitors.

Python
import requests

def get_rankings(keyword: str) -> list:
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers={'x-api-key': API_KEY},
        json={'platform': 'google', 'query': keyword}, timeout=10)
    rankings = []
    for i, r in enumerate(resp.json().get('organic', [])[:20], 1):
        domain = r.get('link', '').split('/')[2] if '//' in r.get('link', '') else ''
        if domain == MY_DOMAIN or any(c in domain for c in COMPETITORS):
            rankings.append({'position': i, 'domain': domain, 'title': r['title']})
    return rankings

Step 3: Compare with previous day

Load yesterday's data and flag position changes above a threshold.

Python
import json, datetime

def compare_rankings(today: dict, yesterday: dict, threshold: int = 3) -> list:
    alerts = []
    for kw in today:
        for entry in today[kw]:
            prev = next((e for e in yesterday.get(kw, []) if e['domain'] == entry['domain']), None)
            if prev:
                change = prev['position'] - entry['position']
                if abs(change) >= threshold:
                    direction = 'up' if change > 0 else 'down'
                    alerts.append(f"{entry['domain']} moved {direction} {abs(change)} positions for '{kw}' (now #{entry['position']})")
            else:
                alerts.append(f"NEW: {entry['domain']} entered top 20 for '{kw}' at #{entry['position']}")
    return alerts

Step 4: Run the daily tracker

Combine everything into a daily run function that saves results and prints alerts.

Python
def daily_track():
    today_data = {}
    for kw in KEYWORDS:
        today_data[kw] = get_rankings(kw)
    date = datetime.date.today().isoformat()
    filename = f'serp_rankings_{date}.json'
    with open(filename, 'w') as f:
        json.dump(today_data, f, indent=2)
    yesterday_file = f'serp_rankings_{(datetime.date.today() - datetime.timedelta(1)).isoformat()}.json'
    try:
        with open(yesterday_file) as f:
            yesterday_data = json.load(f)
        alerts = compare_rankings(today_data, yesterday_data)
        for a in alerts: print(f'ALERT: {a}')
    except FileNotFoundError:
        print('First run, no comparison data yet.')

daily_track()

Python Example

Python
# Run as a cron job: 0 8 * * * python serp_tracker.py
import requests, os, json, datetime
H = {'x-api-key': os.environ['SCAVIO_API_KEY']}

def track(keywords, competitors):
    for kw in keywords:
        data = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
            json={'platform': 'google', 'query': kw}, timeout=10).json()
        for i, r in enumerate(data.get('organic', [])[:20], 1):
            domain = r.get('link', '').split('/')[2] if '//' in r.get('link', '') else ''
            if any(c in domain for c in competitors):
                print(f'[{i:2d}] {domain:30s} | {kw}')

JavaScript Example

JavaScript
async function track(keywords, competitors) {
  for (const kw of keywords) {
    const data = await fetch('https://api.scavio.dev/api/v1/search', {
      method: 'POST', headers: {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'},
      body: JSON.stringify({platform: 'google', query: kw})
    }).then(r => r.json());
    (data.organic || []).forEach((r, i) => {
      const domain = new URL(r.link).hostname;
      if (competitors.some(c => domain.includes(c))) console.log(`[${i+1}] ${domain} | ${kw}`);
    });
  }
}

Expected Output

JSON
Daily SERP ranking reports with position change alerts. Tracks competitor and own-domain positions for target keywords.

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+ installed. requests library installed. A Scavio API key from scavio.dev. A list of target keywords and competitor domains. A Scavio API key gives you 500 free credits per month.

Yes. The free tier includes 500 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

Learn how to build an automated SERP tracker that monitors competitor rankings daily and alerts you to position changes.