Overview
Audit Apollo.io contact lists by verifying each contact's current association with their listed company via Google search. Flag stale records before they bounce and damage sender reputation.
Trigger
CSV export from Apollo or scheduled weekly audit
Schedule
Weekly or before each campaign
Workflow Steps
Export contacts from Apollo
Pull the target contact list from Apollo.io as CSV with name, title, company, domain, and email fields.
Search each contact
For each row, query Google for the contact name plus company domain. Check if the person still appears associated with the company in search results.
Score confidence
Count matching signals: LinkedIn profile at company, team page mention, press quote, conference bio. More signals means higher confidence the contact is still valid.
Flag stale records
Contacts with zero matching signals are flagged as likely stale. Contacts with 1 signal are marked for manual review. Contacts with 2+ signals are marked as verified.
Generate audit report
Output a CSV with original fields plus verification status, confidence score, and signal details. Summary stats show what percentage of the list is stale.
Python Implementation
import requests, os, csv, json
H = {'x-api-key': os.environ['SCAVIO_API_KEY']}
def verify_contact(name, company, domain):
r = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
json={'platform': 'google', 'query': f'{name} {company} {domain}'},
timeout=10).json()
organic = r.get('organic', [])[:5]
signals = []
for o in organic:
link = o.get('link', '').lower()
title = o.get('title', '').lower()
if domain.lower() in link or name.lower().split()[0] in title:
signals.append(o.get('title', '')[:80])
return {
'name': name, 'company': company,
'status': 'verified' if len(signals) >= 2 else 'review' if len(signals) == 1 else 'stale',
'confidence': min(len(signals) / 3, 1.0),
'signals': signals,
}
# Process CSV
with open('apollo_export.csv') as f:
reader = csv.DictReader(f)
results = []
for row in reader:
result = verify_contact(row['name'], row['company'], row['domain'])
results.append(result)
print(f"[{result['status'].upper()}] {result['name']} @ {result['company']}")
stale = sum(1 for r in results if r['status'] == 'stale')
print(f"\nAudit: {stale}/{len(results)} contacts flagged as stale ({stale/len(results)*100:.1f}%)")JavaScript Implementation
const H = {"x-api-key": process.env.SCAVIO_API_KEY, "Content-Type": "application/json"};
async function verifyContact(name, company, domain) {
const r = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST", headers: H,
body: JSON.stringify({platform: "google", query: `${name} ${company} ${domain}`})
}).then(r => r.json());
const organic = (r.organic || []).slice(0, 5);
const signals = organic.filter(o =>
(o.link || "").toLowerCase().includes(domain.toLowerCase()) ||
(o.title || "").toLowerCase().includes(name.toLowerCase().split(" ")[0])
).map(o => (o.title || "").slice(0, 80));
return {
name, company,
status: signals.length >= 2 ? "verified" : signals.length === 1 ? "review" : "stale",
confidence: Math.min(signals.length / 3, 1),
signals,
};
}
const contacts = [
{name: "Jane Smith", company: "Acme Corp", domain: "acme.com"},
{name: "John Doe", company: "Old Startup", domain: "oldstartup.io"},
];
(async () => {
const results = [];
for (const c of contacts) {
const r = await verifyContact(c.name, c.company, c.domain);
results.push(r);
console.log(`[${r.status.toUpperCase()}] ${r.name} @ ${r.company}`);
}
const stale = results.filter(r => r.status === "stale").length;
console.log(`\nAudit: ${stale}/${results.length} contacts flagged as stale`);
})();Platforms Used
Web search with knowledge graph, PAA, and AI overviews