Workflow

Agency SEO Report Weekly

Automated weekly SEO reports for agency clients. White-label rank tracking, SERP features, and competitor analysis from raw SERP data.

Overview

This workflow generates weekly SEO reports for all agency clients from raw SERP data. It tracks keyword rankings, monitors SERP feature changes, identifies competitor movements, and produces white-labeled reports in the agency's branding. Replaces per-client tool licenses with a flat API cost.

Trigger

Cron schedule (every Monday at 6:00 AM UTC)

Schedule

Runs every Monday at 6:00 AM UTC

Workflow Steps

1

Load client configurations

Read each client's domain, tracked keywords, and competitor domains from the agency's client database.

2

Track rankings for each client

Call Scavio for each client's keywords to get current positions, SERP features, and competitor presence.

3

Compare against previous week

Diff current rankings against stored baselines to identify improvements, drops, and feature changes.

4

Generate per-client reports

Build a structured report per client with ranking summary, notable changes, and competitor movements.

5

Deliver reports

Send reports via email, upload to client portal, or push to white-label dashboard.

Python Implementation

Python
import requests
import json
from pathlib import Path
from datetime import datetime

API_KEY = "your_scavio_api_key"

CLIENTS = [
    {"name": "Client A", "domain": "clienta.com", "keywords": ["seo agency austin", "local seo services texas", "small business seo"]},
    {"name": "Client B", "domain": "clientb.com", "keywords": ["saas marketing strategy", "b2b content marketing", "demand generation"]},
]

def track_keyword(keyword: str, domain: str) -> dict:
    res = requests.post(
        "https://api.scavio.dev/api/v1/search",
        headers={"x-api-key": API_KEY},
        json={"platform": "google", "query": keyword, "num": 20},
        timeout=15,
    )
    res.raise_for_status()
    data = res.json()
    position = None
    for item in data.get("organic", []):
        if domain in item.get("link", ""):
            position = item.get("position")
            break
    return {
        "keyword": keyword,
        "position": position,
        "has_ai_overview": bool(data.get("ai_overview")),
        "top_competitors": [r.get("link", "").split("/")[2] if "/" in r.get("link", "") else "" for r in data.get("organic", [])[:5]],
    }

def generate_client_report(client: dict) -> dict:
    results = [track_keyword(kw, client["domain"]) for kw in client["keywords"]]
    ranked = [r for r in results if r["position"]]
    avg_pos = sum(r["position"] for r in ranked) / max(len(ranked), 1)

    return {
        "client": client["name"],
        "domain": client["domain"],
        "date": datetime.utcnow().strftime("%Y-%m-%d"),
        "keywords_tracked": len(results),
        "keywords_ranking": len(ranked),
        "avg_position": round(avg_pos, 1),
        "top_ranking": min((r["position"] for r in ranked), default=None),
        "ai_overview_exposure": sum(1 for r in results if r["has_ai_overview"]),
        "results": results,
    }

def run():
    date = datetime.utcnow().strftime("%Y-%m-%d")
    total_credits = sum(len(c["keywords"]) for c in CLIENTS)

    for client in CLIENTS:
        report = generate_client_report(client)
        Path(f"report_{client['name'].lower().replace(' ', '_')}_{date}.json").write_text(json.dumps(report, indent=2))
        print(f"{report['client']}: {report['keywords_ranking']}/{report['keywords_tracked']} ranking, avg #{report['avg_position']}")

    print(f"\nTotal credits used: {total_credits}")

if __name__ == "__main__":
    run()

JavaScript Implementation

JavaScript
const API_KEY = "your_scavio_api_key";

const CLIENTS = [
  { name: "Client A", domain: "clienta.com", keywords: ["seo agency austin", "local seo services texas"] },
  { name: "Client B", domain: "clientb.com", keywords: ["saas marketing strategy", "b2b content marketing"] },
];

async function trackKeyword(keyword, domain) {
  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: 20 }),
  });
  if (!res.ok) throw new Error(`scavio ${res.status}`);
  const data = await res.json();
  let position = null;
  for (const item of data.organic ?? []) {
    if (item.link?.includes(domain)) { position = item.position; break; }
  }
  return { keyword, position, hasAiOverview: !!data.ai_overview };
}

for (const client of CLIENTS) {
  const results = [];
  for (const kw of client.keywords) results.push(await trackKeyword(kw, client.domain));
  const ranked = results.filter((r) => r.position);
  const avg = ranked.reduce((s, r) => s + r.position, 0) / Math.max(ranked.length, 1);
  console.log(`${client.name}: ${ranked.length}/${results.length} ranking, avg #${Math.round(avg * 10) / 10}`);
}

Platforms Used

Google

Web search with knowledge graph, PAA, and AI overviews

Frequently Asked Questions

This workflow generates weekly SEO reports for all agency clients from raw SERP data. It tracks keyword rankings, monitors SERP feature changes, identifies competitor movements, and produces white-labeled reports in the agency's branding. Replaces per-client tool licenses with a flat API cost.

This workflow uses a cron schedule (every monday at 6:00 am utc). Runs every Monday at 6:00 AM UTC.

This workflow uses the following Scavio platforms: google. Each platform is called via the same unified API endpoint.

Yes. Scavio's free tier includes 250 credits per month with no credit card required. That is enough to test and validate this workflow before scaling it.

Agency SEO Report Weekly

Automated weekly SEO reports for agency clients. White-label rank tracking, SERP features, and competitor analysis from raw SERP data.