Overview
This workflow runs every Monday morning, queries Google for a list of target keywords, records the position of your domain in the organic results, and compiles a report showing position changes compared to the previous week. The output is a structured JSON or CSV file that can feed dashboards, email digests, or Slack notifications.
Trigger
Cron schedule (every Monday at 7 AM UTC)
Schedule
Runs every Monday at 7 AM UTC
Workflow Steps
Load keyword list
Read the target keywords and associated domains from a configuration file or database.
Query Google for each keyword
Call the Scavio API with platform google for each keyword, requesting enough results to cover the first two pages.
Find domain positions
Scan the organic results for each keyword and record the position where the target domain appears. Mark as not-found if absent from results.
Compare with previous week
Load last week's positions from storage and compute the delta for each keyword.
Generate report
Build a structured report with keyword, current position, previous position, and change. Export as JSON and optionally CSV.
Python Implementation
import requests
import json
from pathlib import Path
from datetime import datetime
API_KEY = "your_scavio_api_key"
DOMAIN = "yourdomain.com"
def get_position(query: str) -> int | None:
res = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"platform": "google", "query": query, "num": 20},
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():
keywords = json.loads(Path("keywords.json").read_text())
history_path = Path("rank_history.json")
previous = json.loads(history_path.read_text()) if history_path.exists() else {}
report = []
for kw in keywords:
pos = get_position(kw)
prev = previous.get(kw)
delta = (prev - pos) if (pos and prev) else None
report.append({
"keyword": kw,
"position": pos,
"previous": prev,
"change": delta,
})
if pos:
previous[kw] = pos
history_path.write_text(json.dumps(previous, indent=2))
date_str = datetime.utcnow().strftime("%Y-%m-%d")
Path(f"seo_report_{date_str}.json").write_text(json.dumps(report, indent=2))
print(f"Report generated: {len(report)} keywords tracked")
if __name__ == "__main__":
run()JavaScript Implementation
const API_KEY = "your_scavio_api_key";
const DOMAIN = "yourdomain.com";
async function getPosition(query) {
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, num: 20 }),
});
if (!res.ok) throw new Error(`scavio ${res.status}`);
const data = await res.json();
const match = data.organic?.find((r) => r.link?.includes(DOMAIN));
return match ? match.position : null;
}
async function run() {
const fs = await import("fs/promises");
const keywords = JSON.parse(await fs.readFile("keywords.json", "utf8"));
let previous = {};
try {
previous = JSON.parse(await fs.readFile("rank_history.json", "utf8"));
} catch {}
const report = [];
for (const kw of keywords) {
const pos = await getPosition(kw);
const prev = previous[kw] ?? null;
const change = pos && prev ? prev - pos : null;
report.push({ keyword: kw, position: pos, previous: prev, change });
if (pos) previous[kw] = pos;
}
await fs.writeFile("rank_history.json", JSON.stringify(previous, null, 2));
const date = new Date().toISOString().slice(0, 10);
await fs.writeFile(
`seo_report_${date}.json`,
JSON.stringify(report, null, 2)
);
console.log(`Report generated: ${report.length} keywords tracked`);
}
run();Platforms Used
Web search with knowledge graph, PAA, and AI overviews