Overview
Searches Google Maps for businesses matching target criteria (niche + location), extracts review count and rating, scores and ranks results, and outputs a lead list sorted by score.
Trigger
Manual trigger or scheduled weekly
Schedule
Manual or weekly
Workflow Steps
Define search parameters
Set target niche (e.g., 'plumber'), target city/region, minimum rating threshold, and minimum review count for qualified leads.
Search Google Maps via SERP API
POST to Scavio search API with query '[niche] in [city]' and platform: google. Extract Google Maps pack results (business name, rating, review count, address, website, phone).
Filter by minimum criteria
Remove businesses below minimum rating (e.g., 3.5) or minimum review count (e.g., 10 reviews). These indicate inactive or low-quality businesses.
Score each lead
Score = (rating * 10) + log10(review_count + 1) * 20. Higher rating and more reviews = higher score. This surfaces active, reputable businesses.
Enrich with website data
For high-scoring leads with a website URL, run a secondary search for '[business name] reviews' to collect additional context.
Output ranked CSV
Write business_name, address, rating, review_count, score, website, phone to a ranked CSV. Top 20 leads ready for outreach.
Python Implementation
import requests
import csv
import math
from datetime import date
SCRAVIO_KEY = "YOUR_API_KEY"
NICHE = "plumber"
CITY = "Austin TX"
MIN_RATING = 3.5
MIN_REVIEWS = 10
OUTPUT_CSV = f"leads_{NICHE}_{CITY.replace(' ', '_')}_{date.today()}.csv"
def search_maps(niche: str, city: str) -> list:
resp = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": SCRAVIO_KEY},
json={"query": f"{niche} in {city}", "platform": "google", "include_local": True, "num": 20}
)
resp.raise_for_status()
data = resp.json()
# Google Maps pack results are in local_results field
return data.get("local_results", data.get("results", []))
def score_lead(rating: float, review_count: int) -> float:
rating_score = rating * 10
review_score = math.log10(review_count + 1) * 20
return round(rating_score + review_score, 2)
def run():
results = search_maps(NICHE, CITY)
leads = []
for r in results:
try:
rating = float(r.get("rating", 0) or 0)
reviews = int(r.get("reviews", r.get("review_count", 0)) or 0)
except (ValueError, TypeError):
continue
if rating < MIN_RATING or reviews < MIN_REVIEWS:
continue
leads.append({
"business_name": r.get("title", r.get("name", "")),
"address": r.get("address", ""),
"rating": rating,
"review_count": reviews,
"score": score_lead(rating, reviews),
"website": r.get("website", ""),
"phone": r.get("phone", "")
})
leads.sort(key=lambda x: x["score"], reverse=True)
with open(OUTPUT_CSV, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["business_name", "address", "rating", "review_count", "score", "website", "phone"])
writer.writeheader()
writer.writerows(leads)
print(f"{len(leads)} qualified leads -> {OUTPUT_CSV}")
for lead in leads[:5]:
print(f" {lead['score']:.1f} | {lead['business_name']} | {lead['rating']} stars | {lead['review_count']} reviews")
if __name__ == "__main__":
run()
JavaScript Implementation
const fetch = require('node-fetch');
const fs = require('fs');
const { stringify } = require('csv-stringify/sync');
const SCRAVIO_KEY = 'YOUR_API_KEY';
const NICHE = 'plumber';
const CITY = 'Austin TX';
const MIN_RATING = 3.5;
const MIN_REVIEWS = 10;
async function searchMaps(niche, city) {
const res = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCRAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `${niche} in ${city}`, platform: 'google', include_local: true, num: 20 })
});
const data = await res.json();
return data.local_results || data.results || [];
}
function scoreLead(rating, reviewCount) {
return Math.round((rating * 10 + Math.log10(reviewCount + 1) * 20) * 100) / 100;
}
async function run() {
const results = await searchMaps(NICHE, CITY);
const leads = results
.map(r => ({
business_name: r.title || r.name || '',
address: r.address || '',
rating: parseFloat(r.rating) || 0,
review_count: parseInt(r.reviews || r.review_count) || 0,
website: r.website || '',
phone: r.phone || ''
}))
.filter(l => l.rating >= MIN_RATING && l.review_count >= MIN_REVIEWS)
.map(l => ({ ...l, score: scoreLead(l.rating, l.review_count) }))
.sort((a, b) => b.score - a.score);
const today = new Date().toISOString().slice(0, 10);
fs.writeFileSync(`leads_${NICHE}_${today}.csv`, stringify(leads, { header: true }));
console.log(`${leads.length} leads found. Top: ${leads[0]?.business_name} (${leads[0]?.score})`);
}
run().catch(console.error);
Platforms Used
Web search with knowledge graph, PAA, and AI overviews