seoclaude-codedashboard

Weekly SEO Dashboard with Claude Code

Build SEO dashboard as a Claude Code skill. Type /weekly-report for rank tracking, competitor analysis, and content gaps. Scavio API + SQLite backend.

9 min

Build an SEO dashboard as a Claude Code skill: type /weekly-report and get rank tracking, AI Overview citations, competitor position changes, and content gap analysis. The architecture: Scavio API for SERP data, SQLite for local storage, and formatted terminal output. No web frontend needed -- the report lives in your coding environment.

Architecture

  • Data collection: Scavio API for rank tracking and AI Overview data
  • Storage: SQLite file in your project directory (portable, no server)
  • Analysis: Python script that compares current vs previous week
  • Output: formatted report printed to terminal via Claude Code skill

Step 1: data collection script

Python
import requests, os, sqlite3, json
from datetime import date

DB_PATH = "seo_tracker.db"
H = {"x-api-key": os.environ["SCAVIO_API_KEY"]}

def init_db():
    conn = sqlite3.connect(DB_PATH)
    conn.execute("""CREATE TABLE IF NOT EXISTS rankings (
        date TEXT, keyword TEXT, position INTEGER, ai_cited INTEGER,
        top_url TEXT, PRIMARY KEY (date, keyword))""")
    conn.commit()
    return conn

def collect_rankings(keywords: list, domain: str):
    conn = init_db()
    today = date.today().isoformat()
    for kw in keywords:
        resp = requests.post("https://api.scavio.dev/api/v1/search",
            headers=H,
            json={"query": kw, "include_ai_overview": True})
        data = resp.json()
        pos = None
        url = None
        for i, r in enumerate(data.get("organic_results", [])):
            if domain in r.get("link", ""):
                pos = i + 1
                url = r.get("link")
                break
        ai_sources = data.get("ai_overview", {}).get("sources", [])
        ai_cited = 1 if any(domain in s.get("link", "") for s in ai_sources) else 0
        conn.execute(
            "INSERT OR REPLACE INTO rankings VALUES (?, ?, ?, ?, ?)",
            (today, kw, pos, ai_cited, url))
    conn.commit()
    conn.close()

keywords = ["your keyword 1", "your keyword 2"]
collect_rankings(keywords, "yoursite.com")

Step 2: weekly report generator

Python
from datetime import timedelta

def weekly_report(domain: str):
    conn = sqlite3.connect(DB_PATH)
    today = date.today()
    week_ago = (today - timedelta(days=7)).isoformat()
    today_str = today.isoformat()

    current = dict(conn.execute(
        "SELECT keyword, position FROM rankings WHERE date = ?",
        (today_str,)).fetchall())
    previous = dict(conn.execute(
        "SELECT keyword, position FROM rankings WHERE date = ?",
        (week_ago,)).fetchall())
    ai_citations = dict(conn.execute(
        "SELECT keyword, ai_cited FROM rankings WHERE date = ?",
        (today_str,)).fetchall())

    report = []
    report.append(f"SEO Report: {week_ago} to {today_str}")
    report.append(f"Domain: {domain}")
    report.append("-" * 60)

    improved = []
    declined = []
    for kw, pos in current.items():
        prev_pos = previous.get(kw)
        ai = "AI cited" if ai_citations.get(kw) else ""
        if prev_pos and pos:
            change = prev_pos - pos
            if change > 0:
                improved.append(f"  +{change} {kw}: #{pos} {ai}")
            elif change < 0:
                declined.append(f"  {change} {kw}: #{pos} {ai}")
        elif pos:
            report.append(f"  NEW {kw}: #{pos} {ai}")

    if improved:
        report.append("\nImproved:")
        report.extend(improved)
    if declined:
        report.append("\nDeclined:")
        report.extend(declined)

    conn.close()
    return "\n".join(report)

print(weekly_report("yoursite.com"))

Step 3: competitor tracking

Python
def competitor_snapshot(keywords: list, competitors: list):
    """Check where competitors rank for your target keywords."""
    snapshot = {}
    for kw in keywords:
        resp = requests.post("https://api.scavio.dev/api/v1/search",
            headers=H, json={"query": kw})
        results = resp.json().get("organic_results", [])
        for comp in competitors:
            for i, r in enumerate(results):
                if comp in r.get("link", ""):
                    snapshot.setdefault(comp, {})[kw] = i + 1
                    break
    return snapshot

# Track 3 competitors x 20 keywords = 20 API calls = $0.10
competitors_data = competitor_snapshot(keywords, ["competitor1.com", "competitor2.com"])

Cost for a weekly dashboard

  • 50 keywords, weekly collection: 50 credits/week = $1/mo
  • 50 keywords + 3 competitor checks: 50 + 50 = 100 credits/week = $2/mo
  • Daily collection (for faster alerts): 50 x 30 = 1,500 credits/mo = $7.50/mo
  • All within the free tier for weekly checks (250 credits/mo)