The Problem
Rankings drop and no one notices for days or weeks. By the time someone checks the SEO dashboard, the damage has compounded. A page that dropped from position 3 to position 15 three days ago has already lost hundreds of clicks. Traditional rank tracking tools update weekly at best and send generic emails that get ignored. There is no real-time alert system that triggers the moment a meaningful ranking change occurs, so recovery always starts late.
The Scavio Solution
Scavio lets you build a lightweight rank monitoring system that runs daily, checks your target keywords on Google, compares positions against your stored baseline, and fires an alert the moment a ranking drops below a configurable threshold. The entire system is a single Python or Node script running on a cron. You define the keywords, the domain, and the drop threshold, and the system handles the rest. Detection happens within 24 hours of the change, not a week later in a dashboard no one opened.
Before
Before Scavio, ranking drops went unnoticed for days or weeks. By the time the SEO team checked the dashboard, recovery was already behind schedule and organic traffic had taken a measurable hit.
After
After Scavio, ranking drops trigger alerts within 24 hours. The SEO team starts recovery the same day the drop occurs, minimizing traffic loss and competitive exposure.
Who It Is For
SEO teams, content marketers, and site owners who need immediate notification when rankings drop instead of discovering changes days later in a dashboard. Anyone who has lost traffic because a ranking drop went unnoticed.
Key Benefits
- Daily rank checking with instant drop alerts
- Configurable thresholds for position changes and minimum positions
- Single script deployment on any cron scheduler
- Alerts via Slack webhook, email, or any HTTP endpoint
- Historical position tracking builds a recoverable baseline
Python Example
import requests
import json
from pathlib import Path
API_KEY = "your_scavio_api_key"
DOMAIN = "yourdomain.com"
DROP_THRESHOLD = 3 # Alert if position drops by 3 or more
def check_rank(keyword: str) -> int | None:
res = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"platform": "google", "query": keyword, "num": 30},
timeout=15,
)
res.raise_for_status()
for item in res.json().get("organic", []):
if DOMAIN in item.get("link", ""):
return item["position"]
return None
def run_rank_alerts(keywords: list[str]):
baseline_path = Path("rank_baseline.json")
baseline = json.loads(baseline_path.read_text()) if baseline_path.exists() else {}
alerts = []
for kw in keywords:
current = check_rank(kw)
previous = baseline.get(kw)
if current and previous and (current - previous) >= DROP_THRESHOLD:
alerts.append({
"keyword": kw,
"previous_position": previous,
"current_position": current,
"drop": current - previous,
})
if current:
baseline[kw] = current
baseline_path.write_text(json.dumps(baseline, indent=2))
if alerts:
print(f"RANK DROP ALERT: {len(alerts)} keywords dropped")
for a in alerts:
print(f" {a['keyword']}: #{a['previous_position']} -> #{a['current_position']} (dropped {a['drop']})")
else:
print(f"All {len(keywords)} keywords stable")
keywords = ["your target keyword", "another keyword", "third keyword"]
run_rank_alerts(keywords)JavaScript Example
const API_KEY = "your_scavio_api_key";
const DOMAIN = "yourdomain.com";
const DROP_THRESHOLD = 3;
async function checkRank(keyword) {
const res = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST",
headers: { "x-api-key": API_KEY, "content-type": "application/json" },
body: JSON.stringify({ platform: "google", query: keyword, num: 30 }),
});
if (!res.ok) throw new Error(`scavio ${res.status}`);
const data = await res.json();
for (const item of data.organic ?? []) {
if (item.link?.includes(DOMAIN)) return item.position;
}
return null;
}
async function runRankAlerts(keywords) {
const fs = await import("fs/promises");
let baseline = {};
try { baseline = JSON.parse(await fs.readFile("rank_baseline.json", "utf8")); } catch {}
const alerts = [];
for (const kw of keywords) {
const current = await checkRank(kw);
const previous = baseline[kw];
if (current && previous && current - previous >= DROP_THRESHOLD) {
alerts.push({ keyword: kw, previousPosition: previous, currentPosition: current, drop: current - previous });
}
if (current) baseline[kw] = current;
}
await fs.writeFile("rank_baseline.json", JSON.stringify(baseline, null, 2));
if (alerts.length) {
console.log(`RANK DROP ALERT: ${alerts.length} keywords dropped`);
for (const a of alerts) console.log(` ${a.keyword}: #${a.previousPosition} -> #${a.currentPosition} (dropped ${a.drop})`);
} else {
console.log(`All ${keywords.length} keywords stable`);
}
}
await runRankAlerts(["your target keyword", "another keyword", "third keyword"]);Platforms Used
Web search with knowledge graph, PAA, and AI overviews