ScavioScavio
ProductPricingDocs
Sign InGet Started
  1. Home
  2. Tutorials
  3. How to Batch SEO Rank Checks Overnight with an API
Tutorial

How to Batch SEO Rank Checks Overnight with an API

Run 4,000+ keyword rank checks overnight using a search API and Python. Schedule, batch, store results in CSV, and wake up to fresh SERP data.

Get Free API KeyAPI Docs

Batch overnight rank checking lets you track thousands of keywords without burning daytime API quota or slowing down production systems. The pattern is straightforward: load keywords from a CSV, loop through them with a short delay, store positions in a results file, and schedule the script with cron. Using the Scavio API at $0.005 per credit, a 4,000-keyword nightly run costs $20 -- compared to $60+ on SerpAPI or $499.95+ on Semrush Business. This tutorial builds a complete overnight batch pipeline in Python.

Prerequisites

  • Python 3.9+ installed
  • requests and csv modules (both in stdlib except requests)
  • A Scavio API key from scavio.dev
  • A CSV file with keywords to track

Walkthrough

Step 1: Prepare your keyword CSV

Create a CSV with columns for keyword and target_url. The script will check each keyword and record where the target URL ranks.

Python
import csv

keywords = [
    {'keyword': 'best crm for startups', 'target_url': 'yoursite.com'},
    {'keyword': 'crm pricing comparison 2026', 'target_url': 'yoursite.com'},
    {'keyword': 'hubspot alternative small business', 'target_url': 'yoursite.com'},
]

with open('keywords.csv', 'w', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=['keyword', 'target_url'])
    writer.writeheader()
    writer.writerows(keywords)
print(f'Wrote {len(keywords)} keywords')

Step 2: Build the rank check function

For each keyword, call the search API and scan organic results for your target domain. Return the position or None if not found in the top results.

Python
import requests, os

API_KEY = os.environ['SCAVIO_API_KEY']

def check_rank(keyword: str, target_domain: str) -> dict:
    resp = requests.post('https://api.scavio.dev/api/v1/search',
        headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
        json={'query': keyword, 'country_code': 'us'})
    resp.raise_for_status()
    for r in resp.json().get('organic_results', []):
        if target_domain in r.get('link', ''):
            return {'keyword': keyword, 'position': r['position'], 'url': r['link']}
    return {'keyword': keyword, 'position': None, 'url': None}

Step 3: Batch through all keywords with rate limiting

Read the CSV, check each keyword with a 0.5-second delay to stay well within rate limits, and collect results. For 4,000 keywords this takes about 35 minutes.

Python
import time

def batch_rank_check(csv_path: str) -> list:
    results = []
    with open(csv_path) as f:
        reader = csv.DictReader(f)
        rows = list(reader)
    print(f'Checking {len(rows)} keywords...')
    for i, row in enumerate(rows):
        result = check_rank(row['keyword'], row['target_url'])
        results.append(result)
        if (i + 1) % 100 == 0:
            print(f'  Checked {i + 1}/{len(rows)}')
        time.sleep(0.5)
    return results

Step 4: Save results with timestamp

Write results to a dated CSV so you can track rank changes over time. Each nightly run produces one file.

Python
from datetime import date

def save_results(results: list) -> str:
    filename = f'ranks_{date.today().isoformat()}.csv'
    with open(filename, 'w', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=['keyword', 'position', 'url'])
        writer.writeheader()
        writer.writerows(results)
    ranked = [r for r in results if r['position'] is not None]
    print(f'Saved {len(results)} results to {filename}')
    print(f'  Ranking: {len(ranked)}, Not found: {len(results) - len(ranked)}')
    return filename

Step 5: Schedule with cron for nightly runs

Add a cron entry to run the script at 2 AM daily. The script finishes well before morning so results are ready when you start work.

Python
# Add to crontab (crontab -e):
# 0 2 * * * cd /path/to/project && SCAVIO_API_KEY=your_key python batch_ranks.py

# Full script entry point:
if __name__ == '__main__':
    results = batch_rank_check('keywords.csv')
    save_results(results)
    cost = len(results) * 0.005
    print(f'Total cost: ${cost:.2f}')

Python Example

Python
import os, csv, time, requests
from datetime import date

API_KEY = os.environ['SCAVIO_API_KEY']
ENDPOINT = 'https://api.scavio.dev/api/v1/search'

def check_rank(keyword: str, target: str) -> dict:
    resp = requests.post(ENDPOINT,
        headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
        json={'query': keyword, 'country_code': 'us'})
    resp.raise_for_status()
    for r in resp.json().get('organic_results', []):
        if target in r.get('link', ''):
            return {'keyword': keyword, 'position': r['position'], 'url': r['link']}
    return {'keyword': keyword, 'position': None, 'url': None}

def main():
    with open('keywords.csv') as f:
        rows = list(csv.DictReader(f))
    results = []
    for i, row in enumerate(rows):
        results.append(check_rank(row['keyword'], row['target_url']))
        if (i + 1) % 100 == 0:
            print(f'Checked {i + 1}/{len(rows)}')
        time.sleep(0.5)
    filename = f'ranks_{date.today()}.csv'
    with open(filename, 'w', newline='') as f:
        w = csv.DictWriter(f, fieldnames=['keyword', 'position', 'url'])
        w.writeheader()
        w.writerows(results)
    ranked = sum(1 for r in results if r['position'])
    print(f'{ranked}/{len(results)} ranking, cost: ${len(results) * 0.005:.2f}')

if __name__ == '__main__':
    main()

JavaScript Example

JavaScript
const fs = require('fs');
const API_KEY = process.env.SCAVIO_API_KEY;

async function checkRank(keyword, target) {
  const resp = await fetch('https://api.scavio.dev/api/v1/search', {
    method: 'POST',
    headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ query: keyword, country_code: 'us' })
  });
  const data = await resp.json();
  const match = (data.organic_results || []).find(r => r.link?.includes(target));
  return { keyword, position: match?.position || null, url: match?.link || null };
}

async function main() {
  const lines = fs.readFileSync('keywords.csv', 'utf8').trim().split('\n').slice(1);
  const results = [];
  for (const line of lines) {
    const [keyword, target] = line.split(',');
    results.push(await checkRank(keyword, target));
    await new Promise(r => setTimeout(r, 500));
  }
  const ranked = results.filter(r => r.position).length;
  console.log(`${ranked}/${results.length} ranking, cost: $${(results.length * 0.005).toFixed(2)}`);
}

main().catch(console.error);

Expected Output

JSON
Checking 4000 keywords...
  Checked 100/4000
  Checked 200/4000
  ...
  Checked 4000/4000
Saved 4000 results to ranks_2026-05-13.csv
  Ranking: 2847, Not found: 1153
Total cost: $20.00

Related Tutorials

  • How to Replace Semrush API Credit Drain with a Lightweight Alternative
  • How to Migrate from Google CSE to a Search API in 2026
  • How to Track AI Overview Citations on a Budget

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 and csv modules (both in stdlib except requests). A Scavio API key from scavio.dev. A CSV file with keywords to track. 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

Run SEO Rank Checks Overnight in Batch Mode

Read more
Workflow

Weekly Rank Check for 4,000 Keywords

Read more
Workflow

Daily Local Rank Tracking Pipeline

Read more
Solution

Build Reliable Local Rank Tracking with Scavio API

Read more

Start Building

Run 4,000+ keyword rank checks overnight using a search API and Python. Schedule, batch, store results in CSV, and wake up to fresh SERP data.

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