Workflow

Daily Local Map Pack Rank Snapshot Pipeline

Track local map pack rankings daily across a grid of geo-points. Generate heatmaps showing rank changes over time.

Overview

Local businesses need to know where they rank in Google Map Pack results across their service area, not just from one location. This workflow runs at 6 AM daily, queries Google for your target keywords from a grid of geo-points across your service area, records your position in the local pack at each point, computes rank changes from the previous day, and generates a heatmap dataset showing where you rank well and where competitors dominate. Track local SEO progress with daily data instead of monthly spot checks.

Trigger

Cron schedule (daily at 6 AM UTC)

Schedule

Daily at 6 AM UTC

Workflow Steps

1

Define grid points

Load the grid of lat/lng points covering your service area. Each point represents a simulated search location.

2

Query each grid point

For each point and target keyword, search Google via Scavio. Extract local pack results and your position.

3

Record positions

Store the rank at each grid point with timestamp. Track which competitors appear above and below you.

4

Compute daily changes

Compare today's positions against yesterday's data. Flag grid points where rank improved or dropped.

5

Generate heatmap data

Output a JSON dataset of grid points with rank values, suitable for rendering a visual heatmap.

Python Implementation

Python
import requests, os, json
from datetime import datetime

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

BUSINESS_NAME = "Acme Plumbing"
KEYWORDS = ["plumber near me", "emergency plumber", "plumbing repair"]

# Grid points covering service area (lat, lng, label)
GRID_POINTS = [
    {"label": "Downtown", "geo": "downtown Austin TX"},
    {"label": "North", "geo": "north Austin TX"},
    {"label": "South", "geo": "south Austin TX"},
    {"label": "East", "geo": "east Austin TX"},
    {"label": "West", "geo": "west Austin TX"},
]

def check_rank(keyword, geo_point):
    """Search from a geo-point and find business rank in results."""
    query = f"{keyword} {geo_point['geo']}"
    r = requests.post("https://api.scavio.dev/api/v1/search", headers=H,
        json={"platform": "google", "query": query}, timeout=10).json()
    local = r.get("local_results", r.get("organic", []))[:10]
    rank = None
    for i, item in enumerate(local):
        title = item.get("title", "").lower()
        if BUSINESS_NAME.lower() in title:
            rank = i + 1
            break
    return {
        "keyword": keyword,
        "geo": geo_point["label"],
        "rank": rank,
        "top_3": [item.get("title", "")[:50] for item in local[:3]],
        "checked_at": datetime.utcnow().isoformat()
    }

heatmap_data = []
for kw in KEYWORDS:
    for point in GRID_POINTS:
        result = check_rank(kw, point)
        heatmap_data.append(result)
        rank_str = str(result["rank"]) if result["rank"] else "not found"
        print(f"[{result['geo']}] {kw}: rank {rank_str}")

found = sum(1 for d in heatmap_data if d["rank"] is not None)
print(f"\nGrid checks: {len(heatmap_data)} | Found in results: {found}")

JavaScript Implementation

JavaScript
const H = {"x-api-key": process.env.SCAVIO_API_KEY, "Content-Type": "application/json"};

const BUSINESS_NAME = "Acme Plumbing";
const KEYWORDS = ["plumber near me", "emergency plumber", "plumbing repair"];
const GRID_POINTS = [
  {label: "Downtown", geo: "downtown Austin TX"},
  {label: "North", geo: "north Austin TX"},
  {label: "South", geo: "south Austin TX"},
  {label: "East", geo: "east Austin TX"},
  {label: "West", geo: "west Austin TX"},
];

async function checkRank(keyword, geoPoint) {
  const r = await fetch("https://api.scavio.dev/api/v1/search", {
    method: "POST", headers: H,
    body: JSON.stringify({platform: "google", query: `${keyword} ${geoPoint.geo}`})
  }).then(r => r.json());
  const local = (r.local_results || r.organic || []).slice(0, 10);
  let rank = null;
  local.forEach((item, i) => {
    if ((item.title || "").toLowerCase().includes(BUSINESS_NAME.toLowerCase())) rank = i + 1;
  });
  return {
    keyword, geo: geoPoint.label, rank,
    top3: local.slice(0, 3).map(i => (i.title || "").slice(0, 50)),
    checkedAt: new Date().toISOString()
  };
}

(async () => {
  const heatmapData = [];
  for (const kw of KEYWORDS) {
    for (const point of GRID_POINTS) {
      const result = await checkRank(kw, point);
      heatmapData.push(result);
      console.log(`[${result.geo}] ${kw}: rank ${result.rank || "not found"}`);
    }
  }
  const found = heatmapData.filter(d => d.rank !== null).length;
  console.log(`\nGrid checks: ${heatmapData.length} | Found in results: ${found}`);
})();

Platforms Used

Google

Web search with knowledge graph, PAA, and AI overviews

Frequently Asked Questions

Local businesses need to know where they rank in Google Map Pack results across their service area, not just from one location. This workflow runs at 6 AM daily, queries Google for your target keywords from a grid of geo-points across your service area, records your position in the local pack at each point, computes rank changes from the previous day, and generates a heatmap dataset showing where you rank well and where competitors dominate. Track local SEO progress with daily data instead of monthly spot checks.

This workflow uses a cron schedule (daily at 6 am utc). Daily at 6 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.

Daily Local Map Pack Rank Snapshot Pipeline

Track local map pack rankings daily across a grid of geo-points. Generate heatmaps showing rank changes over time.