A rank tracker is just a script that runs a Google search, finds your domain in the organic results, and records the position. You don't need a $129/mo SE Ranking subscription to do that. This tutorial builds a daily tracker that takes a list of keywords plus your domain, calls the Scavio Google endpoint at `POST https://api.scavio.dev/api/v1/google`, finds your spot in the `results` array, and writes a dated CSV row you can chart. A full query costs 2 credits ($0.01); a light query that only returns organic results costs 1 credit ($0.005). Tracking 50 keywords daily runs about $7.50/month at 2 credits each, or $3.75/month light. One gotcha up front: rank is per-location and per-search, so pin your country and language and don't panic over a single bad day.
Prerequisites
- A Scavio API key (50 free credits on signup, no card) from scavio.dev
- Python 3.9+ or Node.js 18+ installed
- Basic comfort running a script from the terminal
- A list of keywords you want to track and your domain (e.g. example.com)
Walkthrough
Step 1: 1. Get your API key and set it as an env var
Sign up at scavio.dev, copy your key from the dashboard, and export it so it never lands in your code. All Scavio REST endpoints authenticate with the header `Authorization: Bearer {API_KEY}`.
export SCAVIO_API_KEY="sk_your_key_here"Step 2: 2. Call the Google endpoint for one keyword
Send a POST to `/api/v1/google` with your keyword as `query`. Set `light_request:false` to get the full response (2 credits) including organic `results`, `questions`, `knowledge_graph`, and `related_searches`. If you only need rankings, set `light_request:true` for 1 credit. Pin `gl` (country) and `hl` (language) so the same location is measured every day.
curl -X POST https://api.scavio.dev/api/v1/google \
-H "Authorization: Bearer $SCAVIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "keyword rank tracker api", "light_request": false, "gl": "us", "hl": "en"}'Step 3: 3. Find your domain in the results array
The response has a `results` array of organic listings. Walk it in order; the first entry whose link contains your domain is your rank. Index 0 means position 1. If your domain never appears, record the rank as null (not in top results) rather than zero.
results = data["results"]
rank = None
for i, item in enumerate(results):
if domain in item.get("link", ""):
rank = i + 1
breakStep 4: 4. Loop your keywords and write a dated CSV row
Iterate over your keyword list, look up the rank for each, and append a row with the date so you build a history you can chart later. One row per keyword per day.
import csv, datetime
stamp = datetime.date.today().isoformat()
with open("ranks.csv", "a", newline="") as f:
w = csv.writer(f)
for kw, rank in tracked.items():
w.writerow([stamp, kw, rank if rank else ""])Step 5: 5. Schedule it daily with cron
Run the script once a day so the history fills in on its own. Add a crontab entry that runs at 8am. Use the same gl/hl every run so the numbers stay comparable.
# crontab -e
0 8 * * * SCAVIO_API_KEY=sk_xxx /usr/bin/python3 /home/me/rank_tracker.py >> /home/me/rank.log 2>&1Python Example
import csv
import datetime
import os
import requests
API_KEY = os.environ["SCAVIO_API_KEY"]
DOMAIN = "example.com"
KEYWORDS = [
"keyword rank tracker api",
"serp api",
"google search api",
]
def get_rank(keyword, domain):
resp = requests.post(
"https://api.scavio.dev/api/v1/google",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"query": keyword, "light_request": False, "gl": "us", "hl": "en"},
timeout=30,
)
resp.raise_for_status()
results = resp.json().get("results", [])
for i, item in enumerate(results):
if domain in item.get("link", ""):
return i + 1
return None
def main():
stamp = datetime.date.today().isoformat()
with open("ranks.csv", "a", newline="") as f:
writer = csv.writer(f)
for kw in KEYWORDS:
rank = get_rank(kw, DOMAIN)
print(f"{stamp} {kw!r} -> {rank if rank else 'not in top results'}")
writer.writerow([stamp, kw, rank if rank else ""])
if __name__ == "__main__":
main()
JavaScript Example
import { writeFile, appendFile } from "node:fs/promises";
const API_KEY = process.env.SCAVIO_API_KEY;
const DOMAIN = "example.com";
const KEYWORDS = [
"keyword rank tracker api",
"serp api",
"google search api",
];
async function getRank(keyword, domain) {
const resp = await fetch("https://api.scavio.dev/api/v1/google", {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
query: keyword,
light_request: false,
gl: "us",
hl: "en",
}),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const data = await resp.json();
const results = data.results || [];
for (let i = 0; i < results.length; i++) {
if ((results[i].link || "").includes(domain)) return i + 1;
}
return null;
}
async function main() {
const stamp = new Date().toISOString().slice(0, 10);
for (const kw of KEYWORDS) {
const rank = await getRank(kw, DOMAIN);
console.log(`${stamp} ${kw} -> ${rank ?? "not in top results"}`);
await appendFile("ranks.csv", `${stamp},${kw},${rank ?? ""}\n`);
}
}
main();
Expected Output
2026-06-30 'keyword rank tracker api' -> 4
2026-06-30 'serp api' -> 12
2026-06-30 'google search api' -> not in top results
ranks.csv now has one dated row per keyword. Append daily and chart the rank column over time. A single full Google call for "keyword rank tracker api" returned 9 organic results plus 8 related searches in one response for 2 credits ($0.01).