Tutorial

How to Build Your Own Rank Tracker API Without Scraping

Build a complete keyword rank tracking API in Python using the Scavio search API. Track daily positions for unlimited keywords without managing any scrapers.

Most rank trackers are built on top of fragile scrapers that break every time Google changes its HTML. By using the Scavio API as the data layer, you can build a rank tracker that returns structured position data without maintaining proxies or parsers. This tutorial builds a lightweight Flask API that accepts keyword and domain inputs, checks Google positions via Scavio, stores results in SQLite, and exposes historical ranking data through a REST endpoint.

Prerequisites

  • Python 3.10 or higher
  • pip install requests flask
  • A Scavio API key
  • Basic understanding of REST API design

Walkthrough

Step 1: Set up the SQLite database

Create a simple table to store keyword, domain, position, and timestamp for each check.

Python
import sqlite3

def init_db(path: str = "rankings.db") -> None:
    conn = sqlite3.connect(path)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS rankings (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            keyword TEXT NOT NULL,
            domain TEXT NOT NULL,
            position INTEGER,
            checked_at TEXT DEFAULT (datetime('now'))
        )
    """)
    conn.commit()
    conn.close()

Step 2: Check rank via Scavio

Query Google through the Scavio API and scan results for the target domain. Return the position or None.

Python
import requests

def check_rank(keyword: str, domain: str) -> int | None:
    r = requests.post(
        "https://api.scavio.dev/api/v1/search",
        headers={"x-api-key": API_KEY},
        json={"query": keyword, "country_code": "us"}
    )
    r.raise_for_status()
    for result in r.json().get("organic_results", []):
        if domain in result.get("link", ""):
            return result["position"]
    return None

Step 3: Store and retrieve rankings

Save each rank check to SQLite and provide a function to query historical data.

Python
def save_rank(keyword: str, domain: str, position: int | None) -> None:
    conn = sqlite3.connect("rankings.db")
    conn.execute("INSERT INTO rankings (keyword, domain, position) VALUES (?, ?, ?)",
                 (keyword, domain, position))
    conn.commit()
    conn.close()

def get_history(keyword: str, domain: str, days: int = 30) -> list[dict]:
    conn = sqlite3.connect("rankings.db")
    rows = conn.execute(
        "SELECT position, checked_at FROM rankings WHERE keyword=? AND domain=? ORDER BY checked_at DESC LIMIT ?",
        (keyword, domain, days)
    ).fetchall()
    conn.close()
    return [{"position": r[0], "date": r[1]} for r in rows]

Step 4: Expose as a Flask API

Create two endpoints: POST /check to trigger a rank check, and GET /history to retrieve stored positions.

Python
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/check", methods=["POST"])
def check():
    data = request.json
    pos = check_rank(data["keyword"], data["domain"])
    save_rank(data["keyword"], data["domain"], pos)
    return jsonify({"keyword": data["keyword"], "domain": data["domain"], "position": pos})

@app.route("/history")
def history():
    kw = request.args["keyword"]
    domain = request.args["domain"]
    return jsonify(get_history(kw, domain))

Python Example

Python
import os
import sqlite3
import requests
from flask import Flask, request, jsonify

API_KEY = os.environ.get("SCAVIO_API_KEY", "your_scavio_api_key")
ENDPOINT = "https://api.scavio.dev/api/v1/search"
DB = "rankings.db"

def init_db():
    conn = sqlite3.connect(DB)
    conn.execute("CREATE TABLE IF NOT EXISTS rankings (id INTEGER PRIMARY KEY AUTOINCREMENT, keyword TEXT, domain TEXT, position INTEGER, checked_at TEXT DEFAULT (datetime('now')))")
    conn.commit()
    conn.close()

def check_rank(keyword: str, domain: str) -> int | None:
    r = requests.post(ENDPOINT, headers={"x-api-key": API_KEY},
                      json={"query": keyword, "country_code": "us"})
    r.raise_for_status()
    for res in r.json().get("organic_results", []):
        if domain in res.get("link", ""):
            return res["position"]
    return None

app = Flask(__name__)

@app.route("/check", methods=["POST"])
def check():
    d = request.json
    pos = check_rank(d["keyword"], d["domain"])
    conn = sqlite3.connect(DB)
    conn.execute("INSERT INTO rankings (keyword, domain, position) VALUES (?, ?, ?)", (d["keyword"], d["domain"], pos))
    conn.commit()
    conn.close()
    return jsonify({"keyword": d["keyword"], "position": pos})

if __name__ == "__main__":
    init_db()
    app.run(port=5000)

JavaScript Example

JavaScript
const API_KEY = process.env.SCAVIO_API_KEY || "your_scavio_api_key";
const ENDPOINT = "https://api.scavio.dev/api/v1/search";

async function checkRank(keyword, domain) {
  const res = await fetch(ENDPOINT, {
    method: "POST",
    headers: { "x-api-key": API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({ query: keyword, country_code: "us" })
  });
  const data = await res.json();
  const match = (data.organic_results || []).find(r => r.link.includes(domain));
  return match ? match.position : null;
}

async function main() {
  const keywords = ["python api tutorial", "rest api guide"];
  const domain = "mysite.com";
  for (const kw of keywords) {
    const pos = await checkRank(kw, domain);
    console.log(`${kw}: ${pos ? "#" + pos : "not ranked"}`);
  }
}
main().catch(console.error);

Expected Output

JSON
POST /check {"keyword": "python api tutorial", "domain": "mysite.com"}
=> {"keyword": "python api tutorial", "position": 6}

GET /history?keyword=python+api+tutorial&domain=mysite.com
=> [{"position": 6, "date": "2026-04-19"}, {"position": 7, "date": "2026-04-18"}]

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.10 or higher. pip install requests flask. A Scavio API key. Basic understanding of REST API design. 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

Build a complete keyword rank tracking API in Python using the Scavio search API. Track daily positions for unlimited keywords without managing any scrapers.