ScavioScavio
ProductPricingDocs
Sign InGet Started
  1. Home
  2. Tutorials
  3. How to Build a DIY Keyword Rank Tracker
Tutorial

How to Build a DIY Keyword Rank Tracker

Build a keyword rank tracker from raw SERP data. Track positions daily in SQLite, detect changes, and alert on rank movements. Python at $0.005/keyword.

Get Free API KeyAPI Docs

Commercial rank trackers charge $30-300/month and check keywords once daily. Building your own tracker with a SERP API gives you full control over check frequency, stored data, and alerting logic. Each keyword check costs $0.005 through Scavio, so tracking 100 keywords daily runs $0.50/day or $15/month, less than most starter plans.

Prerequisites

  • Python 3.8+
  • requests library
  • A Scavio API key from scavio.dev
  • SQLite3 (included with Python)

Walkthrough

Step 1: Set up the rank tracking database

Create a SQLite database to store daily rank positions.

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'}

db = sqlite3.connect('rank_tracker.db')
db.execute('''CREATE TABLE IF NOT EXISTS ranks (
    keyword TEXT, domain TEXT, position INTEGER,
    title TEXT, checked_at TEXT
)''')
db.execute('CREATE INDEX IF NOT EXISTS idx_kw ON ranks(keyword, checked_at)')
db.commit()

MY_DOMAIN = 'scavio.dev'
KEYWORDS = ['serp api', 'search api python', 'google search api',
            'web scraping api', 'ai agent search tool']
print(f'Tracking {len(KEYWORDS)} keywords for {MY_DOMAIN}')

Step 2: Check keyword rankings

Fetch SERP results and find your domain position for each keyword.

Python
def check_rank(keyword, domain):
    data = requests.post('https://api.scavio.dev/api/v1/search',
        headers=SH, json={'query': keyword, 'country_code': 'us'}).json()
    organic = data.get('organic_results', [])
    now = datetime.now().isoformat()
    for r in organic[:50]:
        link = r.get('link', '')
        if domain in link:
            pos = r.get('position', 0)
            title = r.get('title', '')[:100]
            db.execute('INSERT INTO ranks VALUES (?,?,?,?,?)',
                (keyword, domain, pos, title, now))
            db.commit()
            return pos
    db.execute('INSERT INTO ranks VALUES (?,?,?,?,?)',
        (keyword, domain, 0, 'Not found', now))
    db.commit()
    return 0

for kw in KEYWORDS:
    pos = check_rank(kw, MY_DOMAIN)
    status = f'#{pos}' if pos else 'Not in top 50'
    print(f'  {kw:30} | {status}')
print(f'Cost: ${len(KEYWORDS) * 0.005:.3f}')

Step 3: Detect rank changes between checks

Compare current positions against previous checks to find movements.

Python
def detect_changes(keyword, domain):
    rows = db.execute(
        'SELECT position, checked_at FROM ranks WHERE keyword=? AND domain=? ORDER BY checked_at DESC LIMIT 2',
        (keyword, domain)).fetchall()
    if len(rows) < 2:
        return None
    current, prev = rows[0][0], rows[1][0]
    if current == prev:
        return None
    change = prev - current  # positive = improved
    return {'keyword': keyword, 'prev': prev, 'current': current, 'change': change}

def report_changes():
    changes = []
    for kw in KEYWORDS:
        c = detect_changes(kw, MY_DOMAIN)
        if c:
            changes.append(c)
    if changes:
        print(f'\n{len(changes)} rank changes:')
        for c in changes:
            arrow = 'UP' if c['change'] > 0 else 'DOWN'
            print(f'  {c["keyword"]:30} | #{c["prev"]} -> #{c["current"]} ({arrow} {abs(c["change"])})')
    else:
        print('No rank changes detected.')
    return changes

report_changes()

Step 4: Schedule daily checks via cron

Automate the tracker to run daily and accumulate history.

Python
def daily_check():
    print(f'Daily rank check: {datetime.now().isoformat()}')
    results = []
    for kw in KEYWORDS:
        pos = check_rank(kw, MY_DOMAIN)
        results.append({'keyword': kw, 'position': pos})
    cost = len(KEYWORDS) * 0.005
    print(f'Checked {len(KEYWORDS)} keywords. Cost: ${cost:.3f}')
    changes = report_changes()
    # Summary
    ranked = [r for r in results if r['position'] > 0]
    avg = sum(r['position'] for r in ranked) / len(ranked) if ranked else 0
    print(f'\nSummary: {len(ranked)}/{len(results)} keywords ranking, avg position: {avg:.1f}')
    print(f'Monthly cost estimate: ${cost * 30:.2f}')

# Cron: 0 6 * * * cd /path/to/project && python rank_tracker.py
daily_check()

Python Example

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

def track(keyword, domain):
    data = requests.post('https://api.scavio.dev/api/v1/search',
        headers=SH, json={'query': keyword, 'country_code': 'us'}).json()
    for r in data.get('organic_results', [])[:50]:
        if domain in r.get('link', ''):
            print(f'{keyword}: {domain} at #{r["position"]}. Cost: $0.005')
            return r['position']
    print(f'{keyword}: {domain} not in top 50')
    return 0

track('serp api', 'scavio.dev')

JavaScript Example

JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
async function track(keyword, domain) {
  const data = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST', headers: SH,
    body: JSON.stringify({ query: keyword, country_code: 'us' })
  }).then(r => r.json());
  const match = (data.organic_results || []).find(r => (r.link || '').includes(domain));
  console.log(match ? `${keyword}: ${domain} at #${match.position}` : `${keyword}: not found`);
}
track('serp api', 'scavio.dev').catch(console.error);

Expected Output

JSON
Tracking 5 keywords for scavio.dev
  serp api                       | #4
  search api python              | #7
  google search api              | #11
  web scraping api               | #6
  ai agent search tool           | #3
Cost: $0.025

Summary: 5/5 keywords ranking, avg position: 6.2
Monthly cost estimate: $0.75

Related Tutorials

  • How to Build a Historical SERP Archive
  • How to Build a Competitive SERP Monitor
  • How to Build a Custom SEO Dashboard with a Search API

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. SQLite3 (included with Python). A Scavio API key gives you 50 free credits on signup.

Yes. The free tier includes 50 credits on signup, 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.

Related Resources

Best Of

Best SEO Rank Tracking APIs in 2026

Read more
Best Of

Best API-Based Rank Trackers for SEO in 2026

Read more
Solution

Build Reliable Local Rank Tracking with Scavio API

Read more
Solution

Run SEO Rank Checks Overnight in Batch Mode

Read more
Use Case

SEO Light User API Workflow

Read more
Workflow

Surfer SEO + SERP API Daily Rank Tracking Flow

Read more

Start Building

Build a keyword rank tracker from raw SERP data. Track positions daily in SQLite, detect changes, and alert on rank movements. Python at $0.005/keyword.

Get Free API KeyRead the Docs
ScavioScavio

Real-time search API for AI agents. Search every platform, not just Google.

Product

  • Features
  • Pricing
  • Dashboard
  • Affiliates

Developers

  • Documentation
  • API Reference
  • Quickstart
  • MCP Integration
  • Python SDK

Alternatives

  • Tavily Alternative
  • SerpAPI Alternative
  • Firecrawl Alternative
  • Exa Alternative

Tools

  • JSON Formatter
  • cURL to Code
  • Token Counter
  • All Tools

© 2026 Scavio. All rights reserved.

Featured on TAAFT
Terms of ServicePrivacy Policy