Overview
This workflow refreshes local business lead data weekly by querying Google for business categories in target locations. It extracts local pack results with business names, ratings, review counts, and addresses, then scores leads by quality signals. The output feeds into CRM imports or outreach automation tools.
Trigger
Cron schedule (every Monday at 7:00 AM UTC)
Schedule
Runs every Monday at 7:00 AM UTC
Workflow Steps
Load categories and target locations
Read the list of business categories and geographic locations to search from configuration.
Search Google for local businesses
Call Scavio with queries like '{category} near {location}' to get local pack and organic results.
Extract and normalize lead data
Parse local pack results for business name, address, phone, rating, review count, and website URL.
Score leads by quality signals
Score each lead by review count (established business), rating (quality), and presence of website (tech savviness).
Export for CRM import
Format scored leads as CSV or JSON for CRM import, with deduplication against previously imported leads.
Python Implementation
import requests
import json
import csv
from pathlib import Path
from datetime import datetime
API_KEY = "your_scavio_api_key"
CATEGORIES = ["plumber", "electrician", "HVAC contractor", "roofing company"]
LOCATIONS = ["Austin TX", "Dallas TX", "San Antonio TX"]
def search_local(category: str, location: str) -> list[dict]:
res = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"platform": "google", "query": f"{category} near {location}"},
timeout=15,
)
res.raise_for_status()
data = res.json()
leads = []
for item in data.get("local_pack", data.get("organic", [])):
leads.append({
"name": item.get("title", item.get("name", "")),
"address": item.get("address", ""),
"phone": item.get("phone", ""),
"rating": item.get("rating"),
"reviews": item.get("reviews", 0),
"website": item.get("link", ""),
"category": category,
"location": location,
})
return leads
def score_lead(lead: dict) -> float:
score = 0
if lead.get("reviews", 0) > 50:
score += 30
elif lead.get("reviews", 0) > 10:
score += 15
if lead.get("rating") and lead["rating"] >= 4.0:
score += 20
if lead.get("website"):
score += 10
if lead.get("phone"):
score += 10
return score
def run():
all_leads = []
seen = set()
for category in CATEGORIES:
for location in LOCATIONS:
leads = search_local(category, location)
for lead in leads:
key = f"{lead['name']}_{lead['address']}"
if key not in seen:
seen.add(key)
lead["score"] = score_lead(lead)
all_leads.append(lead)
all_leads.sort(key=lambda x: x["score"], reverse=True)
date = datetime.utcnow().strftime("%Y-%m-%d")
# JSON output
Path(f"local_leads_{date}.json").write_text(json.dumps(all_leads, indent=2))
# CSV for CRM import
csv_path = Path(f"local_leads_{date}.csv")
with csv_path.open("w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["name", "address", "phone", "rating", "reviews", "website", "category", "location", "score"])
writer.writeheader()
writer.writerows(all_leads)
print(f"Generated {len(all_leads)} leads from {len(CATEGORIES) * len(LOCATIONS)} searches")
print(f"Credits used: {len(CATEGORIES) * len(LOCATIONS)}")
for lead in all_leads[:5]:
print(f" [{lead['score']}] {lead['name']} - {lead.get('rating', 'N/A')} stars, {lead['reviews']} reviews")
if __name__ == "__main__":
run()JavaScript Implementation
const API_KEY = "your_scavio_api_key";
const CATEGORIES = ["plumber", "electrician", "HVAC contractor"];
const LOCATIONS = ["Austin TX", "Dallas TX"];
async function searchLocal(category, location) {
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: `${category} near ${location}` }),
});
if (!res.ok) throw new Error(`scavio ${res.status}`);
const data = await res.json();
return (data.local_pack ?? data.organic ?? []).map((item) => ({
name: item.title ?? item.name ?? "", rating: item.rating ?? null, reviews: item.reviews ?? 0, category, location,
}));
}
const allLeads = [];
for (const cat of CATEGORIES) {
for (const loc of LOCATIONS) allLeads.push(...await searchLocal(cat, loc));
}
allLeads.sort((a, b) => b.reviews - a.reviews);
console.log(`Generated ${allLeads.length} leads from ${CATEGORIES.length * LOCATIONS.length} searches`);
for (const l of allLeads.slice(0, 5)) console.log(` ${l.name}: ${l.rating ?? "N/A"} stars, ${l.reviews} reviews`);Platforms Used
Web search with knowledge graph, PAA, and AI overviews