Workflow

AI Overview Weekly Tracker

Weekly tracking of AI Overview presence for target keywords. Detect when your brand appears, disappears, or gets replaced in Google AI answers.

Overview

This workflow tracks AI Overview presence weekly for a list of target keywords. It checks whether AI Overviews exist for each keyword, whether your brand is mentioned, which competitors appear, and how the content has changed since last week. The output is a structured report showing AIO visibility trends over time.

Trigger

Cron schedule (every Monday at 9 AM UTC)

Schedule

Runs every Monday at 9 AM UTC

Workflow Steps

1

Load target keywords

Read the keyword list and brand names to track from configuration.

2

Query Google with AI Overview enabled

Call Scavio with ai_overview: true for each keyword to capture the AI Overview content.

3

Parse AI Overview content

Extract text, cited sources, and brand mentions from the AI Overview response field.

4

Compare against last week

Diff current AI Overview presence and content against stored history.

5

Detect changes

Flag keywords where brand appeared, disappeared, or where AIO content changed significantly.

6

Generate weekly AIO report

Compile all findings into a structured report with visibility score and change log.

Python Implementation

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

API_KEY = "your_scavio_api_key"
BRAND = "yourbrand"
COMPETITORS = ["competitor1", "competitor2"]

def check_aio(keyword: str) -> dict:
    res = requests.post(
        "https://api.scavio.dev/api/v1/search",
        headers={"x-api-key": API_KEY},
        json={"platform": "google", "query": keyword, "ai_overview": True},
        timeout=15,
    )
    res.raise_for_status()
    data = res.json()
    aio = data.get("ai_overview")

    result = {
        "keyword": keyword,
        "has_aio": bool(aio),
        "brand_mentioned": False,
        "competitors_mentioned": [],
        "aio_text": "",
    }

    if aio:
        text = aio.get("text", "")
        result["aio_text"] = text[:500]
        result["brand_mentioned"] = BRAND.lower() in text.lower()
        result["competitors_mentioned"] = [c for c in COMPETITORS if c.lower() in text.lower()]

    return result

def run():
    keywords = json.loads(Path("aio_keywords.json").read_text())
    history_path = Path("aio_history.json")
    history = json.loads(history_path.read_text()) if history_path.exists() else {}

    current = {}
    changes = []

    for kw in keywords:
        result = check_aio(kw)
        current[kw] = result

        prev = history.get(kw, {})
        if prev:
            if prev.get("brand_mentioned") and not result["brand_mentioned"]:
                changes.append({"keyword": kw, "type": "brand_disappeared"})
            elif not prev.get("brand_mentioned") and result["brand_mentioned"]:
                changes.append({"keyword": kw, "type": "brand_appeared"})
            if not prev.get("has_aio") and result["has_aio"]:
                changes.append({"keyword": kw, "type": "aio_added"})
            elif prev.get("has_aio") and not result["has_aio"]:
                changes.append({"keyword": kw, "type": "aio_removed"})

    history_path.write_text(json.dumps(current, indent=2))

    # Calculate visibility score
    total_with_aio = sum(1 for r in current.values() if r["has_aio"])
    brand_visible = sum(1 for r in current.values() if r["brand_mentioned"])
    visibility_score = round((brand_visible / max(total_with_aio, 1)) * 100)

    report = {
        "date": datetime.utcnow().strftime("%Y-%m-%d"),
        "keywords_tracked": len(keywords),
        "keywords_with_aio": total_with_aio,
        "brand_visible_in": brand_visible,
        "visibility_score": visibility_score,
        "changes": changes,
    }

    Path(f"aio_report_{report['date']}.json").write_text(json.dumps(report, indent=2))
    print(f"AIO Visibility: {visibility_score}% ({brand_visible}/{total_with_aio} AIOs mention brand)")
    print(f"Changes this week: {len(changes)}")
    for c in changes:
        print(f"  {c['keyword']}: {c['type']}")

if __name__ == "__main__":
    run()

JavaScript Implementation

JavaScript
const API_KEY = "your_scavio_api_key";
const BRAND = "yourbrand";
const COMPETITORS = ["competitor1", "competitor2"];

async function checkAio(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, ai_overview: true }),
  });
  if (!res.ok) throw new Error(`scavio ${res.status}`);
  const data = await res.json();
  const aio = data.ai_overview;
  const result = { keyword, hasAio: !!aio, brandMentioned: false, competitorsMentioned: [], aioText: "" };
  if (aio) {
    const text = aio.text ?? "";
    result.aioText = text.slice(0, 500);
    result.brandMentioned = text.toLowerCase().includes(BRAND.toLowerCase());
    result.competitorsMentioned = COMPETITORS.filter((c) => text.toLowerCase().includes(c.toLowerCase()));
  }
  return result;
}

async function run() {
  const fs = await import("fs/promises");
  const keywords = JSON.parse(await fs.readFile("aio_keywords.json", "utf8"));
  let history = {};
  try { history = JSON.parse(await fs.readFile("aio_history.json", "utf8")); } catch {}

  const current = {};
  const changes = [];

  for (const kw of keywords) {
    const result = await checkAio(kw);
    current[kw] = result;
    const prev = history[kw] ?? {};
    if (prev.brandMentioned && !result.brandMentioned) changes.push({ keyword: kw, type: "brand_disappeared" });
    else if (!prev.brandMentioned && result.brandMentioned) changes.push({ keyword: kw, type: "brand_appeared" });
    if (!prev.hasAio && result.hasAio) changes.push({ keyword: kw, type: "aio_added" });
    else if (prev.hasAio && !result.hasAio) changes.push({ keyword: kw, type: "aio_removed" });
  }

  await fs.writeFile("aio_history.json", JSON.stringify(current, null, 2));

  const totalWithAio = Object.values(current).filter((r) => r.hasAio).length;
  const brandVisible = Object.values(current).filter((r) => r.brandMentioned).length;
  const visibilityScore = Math.round((brandVisible / Math.max(totalWithAio, 1)) * 100);

  const date = new Date().toISOString().slice(0, 10);
  const report = { date, keywordsTracked: keywords.length, keywordsWithAio: totalWithAio, brandVisibleIn: brandVisible, visibilityScore, changes };
  await fs.writeFile(`aio_report_${date}.json`, JSON.stringify(report, null, 2));
  console.log(`AIO Visibility: ${visibilityScore}% (${brandVisible}/${totalWithAio} AIOs mention brand)`);
  console.log(`Changes: ${changes.length}`);
  for (const c of changes) console.log(`  ${c.keyword}: ${c.type}`);
}

run();

Platforms Used

Google

Web search with knowledge graph, PAA, and AI overviews

Frequently Asked Questions

This workflow tracks AI Overview presence weekly for a list of target keywords. It checks whether AI Overviews exist for each keyword, whether your brand is mentioned, which competitors appear, and how the content has changed since last week. The output is a structured report showing AIO visibility trends over time.

This workflow uses a cron schedule (every monday at 9 am utc). Runs every Monday at 9 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.

AI Overview Weekly Tracker

Weekly tracking of AI Overview presence for target keywords. Detect when your brand appears, disappears, or gets replaced in Google AI answers.