Overview
Agencies and local service providers need a steady pipeline of business leads. This workflow runs every morning, searches Google Maps via Scavio for businesses in your target categories and locations, extracts contact information (name, address, phone, website, rating), deduplicates against your existing database, and exports fresh leads. Searching 5 categories across 3 locations costs about 15 credits per day ($0.075).
Trigger
Cron 6 AM UTC daily
Schedule
Daily 6 AM
Workflow Steps
Load Target Configuration
Read target business categories (plumbers, dentists, etc.) and locations from a config file.
Search Google Maps via Scavio
For each category-location pair, call Scavio search on Google Maps to find matching businesses.
Extract Contact Information
Parse each result for business name, address, phone number, website, rating, and review count.
Deduplicate Against Database
Check each lead against your existing leads database by phone or website to avoid duplicates.
Export Fresh Leads
Write new leads to a CSV or push to your CRM via webhook for immediate follow-up.
Python Implementation
import requests, os, json, csv
from pathlib import Path
from datetime import date
API_KEY = os.environ["SCAVIO_API_KEY"]
SH = {"x-api-key": API_KEY, "Content-Type": "application/json"}
CONFIG_FILE = Path("lead_gen_config.json")
SEEN_FILE = Path("seen_leads.json")
LEADS_DIR = Path("leads")
LEADS_DIR.mkdir(exist_ok=True)
def search_maps(query: str) -> list:
resp = requests.post(
"https://api.scavio.dev/api/v1/search",
headers=SH,
json={"query": query, "platform": "google-maps"},
timeout=15,
)
resp.raise_for_status()
return resp.json().get("organic", [])
def extract_lead(result: dict, category: str, location: str) -> dict:
return {
"name": result.get("title", ""),
"address": result.get("address", ""),
"phone": result.get("phone", ""),
"website": result.get("website", result.get("url", "")),
"rating": result.get("rating"),
"reviews": result.get("reviews"),
"category": category,
"location": location,
}
def run():
config = json.loads(CONFIG_FILE.read_text())
seen = set()
if SEEN_FILE.exists():
seen = set(json.loads(SEEN_FILE.read_text()))
new_leads = []
for cat in config["categories"]:
for loc in config["locations"]:
query = f"{cat} in {loc}"
results = search_maps(query)
for r in results:
lead = extract_lead(r, cat, loc)
dedup_key = lead["phone"] or lead["website"] or lead["name"]
if dedup_key and dedup_key not in seen:
seen.add(dedup_key)
new_leads.append(lead)
SEEN_FILE.write_text(json.dumps(list(seen)))
if new_leads:
out = LEADS_DIR / f"leads_{date.today()}.csv"
with open(out, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=new_leads[0].keys())
writer.writeheader()
writer.writerows(new_leads)
print(f"Generated {len(new_leads)} new leads on {date.today()}")
for l in new_leads[:10]:
print(f" {l['name']} | {l['phone']} | {l['category']} | {l['location']}")
run()JavaScript Implementation
const SH = {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'};
const fs = await import('fs');
const config = JSON.parse(fs.readFileSync('lead_gen_config.json', 'utf8'));
const LEADS_DIR = 'leads';
try { fs.mkdirSync(LEADS_DIR); } catch {}
let seen = new Set();
try { seen = new Set(JSON.parse(fs.readFileSync('seen_leads.json', 'utf8'))); } catch {}
async function searchMaps(query) {
const r = await fetch('https://api.scavio.dev/api/v1/search', {method:'POST', headers:SH, body:JSON.stringify({query, platform:'google-maps'})});
return (await r.json()).organic || [];
}
const newLeads = [];
for (const cat of config.categories) {
for (const loc of config.locations) {
const results = await searchMaps(cat+' in '+loc);
for (const r of results) {
const lead = {name:r.title||'', address:r.address||'', phone:r.phone||'', website:r.website||r.url||'', rating:r.rating, reviews:r.reviews, category:cat, location:loc};
const dedupKey = lead.phone || lead.website || lead.name;
if (dedupKey && !seen.has(dedupKey)) {
seen.add(dedupKey);
newLeads.push(lead);
}
}
}
}
fs.writeFileSync('seen_leads.json', JSON.stringify([...seen]));
if (newLeads.length) {
const header = Object.keys(newLeads[0]).join(',');
const rows = newLeads.map(l => Object.values(l).map(v => '"'+(v===null||v===undefined?'':String(v).replace(/"/g,'""'))+'"').join(','));
const today = new Date().toISOString().split('T')[0];
fs.writeFileSync(LEADS_DIR+'/leads_'+today+'.csv', header+'\n'+rows.join('\n')+'\n');
}
console.log('Generated '+newLeads.length+' new leads');
newLeads.slice(0,10).forEach(l => console.log(' '+l.name+' | '+l.phone+' | '+l.category+' | '+l.location));Platforms Used
Google Maps
Local business search with ratings and contact info