seodashboardapi

Custom SEO Dashboard: Raw API Architecture

Build a white-label SEO dashboard with raw SERP data instead of Ahrefs or Semrush. Architecture: API layer, PostgreSQL, chart frontend. Full code included.

10 min

You can replace a $500/month SEMrush or Ahrefs enterprise subscription with a custom SEO dashboard built on raw API data for under $30/month in API costs. The architecture: schedule SERP queries via DataForSEO queue ($0.0006/query) or Scavio ($0.005/credit), store results in a database, and visualize in Looker Studio or a custom frontend.

Architecture overview

The pipeline has four stages: collection, storage, transformation, and visualization. Collection runs on a cron schedule pulling SERP data. Storage is any SQL database or even Google Sheets for small scale. Transformation normalizes positions, calculates deltas, and flags changes. Visualization is Looker Studio (free), Grafana, or a custom Next.js dashboard.

Python
# Architecture: SERP API -> SQLite -> Transform -> Dashboard
#
# [Cron/n8n scheduler]
#     |
#     v
# [SERP API] (DataForSEO queue or Scavio)
#     |
#     v
# [SQLite / PostgreSQL]
#     |
#     v
# [Transform: rank deltas, feature detection]
#     |
#     v
# [Looker Studio / Grafana / Custom UI]

Data collection layer

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

DB_PATH = "serp_data.db"

def init_db():
    conn = sqlite3.connect(DB_PATH)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS serp_results (
            id INTEGER PRIMARY KEY,
            keyword TEXT,
            domain TEXT,
            position INTEGER,
            serp_features TEXT,
            captured_at TEXT
        )
    """)
    conn.commit()
    return conn

def collect_serp(keyword: str, conn: sqlite3.Connection):
    """Pull SERP data via Scavio and store positions."""
    resp = requests.post(
        "https://api.scavio.dev/api/v1/search",
        headers={"x-api-key": os.environ["SCAVIO_API_KEY"]},
        json={"query": keyword, "platform": "google", "num_results": 50},
        timeout=15,
    )
    data = resp.json()
    now = datetime.utcnow().isoformat()

    features = []
    if data.get("ai_overview"):
        features.append("ai_overview")
    if data.get("people_also_ask"):
        features.append("paa")
    if data.get("local_pack"):
        features.append("local_pack")

    for i, result in enumerate(data.get("organic_results", []), 1):
        domain = result.get("displayed_link", "").split("/")[0]
        conn.execute(
            "INSERT INTO serp_results (keyword, domain, position, serp_features, captured_at) VALUES (?, ?, ?, ?, ?)",
            (keyword, domain, i, json.dumps(features), now),
        )
    conn.commit()

# Daily collection: 200 keywords = 200 credits = $1.00/day on Scavio
# Or $0.12/day on DataForSEO queue

Transformation: rank deltas and alerts

Python
def compute_rank_deltas(conn: sqlite3.Connection, keyword: str) -> list:
    """Compare today's positions to yesterday's."""
    rows = conn.execute("""
        SELECT domain, position, captured_at
        FROM serp_results
        WHERE keyword = ?
        ORDER BY captured_at DESC
    """, (keyword,)).fetchall()

    # Group by date
    by_date = {}
    for domain, pos, captured in rows:
        date = captured[:10]
        if date not in by_date:
            by_date[date] = {}
        by_date[date][domain] = pos

    dates = sorted(by_date.keys(), reverse=True)
    if len(dates) < 2:
        return []

    today, yesterday = by_date[dates[0]], by_date[dates[1]]
    deltas = []
    for domain, pos in today.items():
        prev = yesterday.get(domain)
        if prev:
            delta = prev - pos  # Positive = improved
            deltas.append({"domain": domain, "position": pos, "delta": delta})

    return sorted(deltas, key=lambda x: abs(x["delta"]), reverse=True)

Visualization: Looker Studio connection

Export your SQLite data to Google Sheets via a simple script, then connect Looker Studio to the sheet. For production, use PostgreSQL with Looker Studio's native PostgreSQL connector. The dashboard shows keyword positions over time, rank deltas, and SERP feature changes.

Python
# Export to CSV for Looker Studio / Sheets import
import csv

def export_for_dashboard(conn: sqlite3.Connection, output_path: str):
    rows = conn.execute("""
        SELECT keyword, domain, position, serp_features,
               DATE(captured_at) as date
        FROM serp_results
        ORDER BY date DESC, keyword, position
    """).fetchall()

    with open(output_path, "w", newline="") as f:
        writer = csv.writer(f)
        writer.writerow(["keyword", "domain", "position", "features", "date"])
        writer.writerows(rows)

# For automated pipelines, push directly to Google Sheets API
# or use n8n's Google Sheets node

Cost comparison: custom vs. enterprise tools

  • SEMrush Pro: $139/month for 500 keywords tracked daily
  • Ahrefs Standard: $249/month for rank tracking + backlinks
  • Custom (DataForSEO queue): 500 keywords x 30 days x $0.0006 = $9/month
  • Custom (Scavio): 500 keywords x 30 days x $0.005 = $75/month, or $30/month on Project plan (7,000 credits)
  • Custom overhead: server ($5-10/month), your time to maintain

When to stay with enterprise tools

Custom dashboards win on cost but lose on convenience. SEMrush and Ahrefs include historical databases going back years, competitor discovery, backlink profiles, and content gap analysis out of the box. If your team lacks engineering time to maintain a pipeline, or you need historical data you have not been collecting, the subscription tools remain worth it. The custom approach works best when you already know exactly which keywords and domains to track.