Overview
Companies with declining review scores or high complaint volumes are actively looking for alternatives. This workflow searches for company reviews daily, extracts sentiment signals, and scores leads based on review pain indicators. A company dropping from 4.5 to 3.2 stars on G2 is a warmer lead than one with stable 4.8 stars.
Trigger
Daily cron at 07:00 UTC
Schedule
Daily at 07:00 UTC
Workflow Steps
Load target companies
Read the list of companies in your ICP (Ideal Customer Profile) that you want to monitor for review changes.
Search for reviews
Query each company name with 'reviews' and 'complaints' modifiers to find recent review content.
Extract review signals
Parse search snippets for star ratings, review counts, and sentiment keywords (complaints, issues, switching, alternative).
Score leads
Assign a lead score based on: declining ratings (+20), complaint volume (+15), 'switching' mentions (+25), recent negative press (+10).
Output ranked list
Sort by score and output the top leads for sales outreach with the specific pain signals found.
Python Implementation
import requests, os, json, re
H = {"x-api-key": os.environ["SCAVIO_API_KEY"], "Content-Type": "application/json"}
PAIN_KEYWORDS = ["complaint", "issue", "problem", "switching", "alternative", "worst", "terrible", "migrating"]
def score_lead(company):
queries = [f'"{company}" reviews 2026', f'"{company}" complaints OR issues']
score = 0
signals = []
for q in queries:
r = requests.post("https://api.scavio.dev/api/v1/search", headers=H,
json={"platform": "google", "query": q}).json()
for o in r.get("organic", [])[:5]:
snippet = (o.get("snippet", "") or "").lower()
for kw in PAIN_KEYWORDS:
if kw in snippet:
score += 10
signals.append(f"{kw} found in: {o.get('title', '')[:50]}")
rating_match = re.search(r'(\d\.\d)\s*/\s*5|rating.*?(\d\.\d)', snippet)
if rating_match:
rating = float(rating_match.group(1) or rating_match.group(2))
if rating < 3.5:
score += 20
signals.append(f"Low rating: {rating}/5")
return {"company": company, "score": score, "signals": signals[:5]}
companies = ["Competitor A", "Competitor B", "Competitor C"]
leads = sorted([score_lead(c) for c in companies], key=lambda x: -x["score"])
for l in leads:
print(f"{l['company']}: score={l['score']}, signals={len(l['signals'])}")JavaScript Implementation
const H = {"x-api-key": process.env.SCAVIO_API_KEY, "Content-Type": "application/json"};
const PAIN_KEYWORDS = ["complaint", "issue", "problem", "switching", "alternative", "worst", "terrible", "migrating"];
async function scoreLead(company) {
const queries = [`"${company}" reviews 2026`, `"${company}" complaints OR issues`];
let score = 0;
const signals = [];
for (const q of queries) {
const r = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST", headers: H,
body: JSON.stringify({platform: "google", query: q})
}).then(r => r.json());
for (const o of (r.organic || []).slice(0, 5)) {
const snippet = (o.snippet || "").toLowerCase();
for (const kw of PAIN_KEYWORDS) {
if (snippet.includes(kw)) {
score += 10;
signals.push(`${kw} in: ${(o.title || "").slice(0, 50)}`);
}
}
const match = snippet.match(/(\d\.\d)\s*\/\s*5|rating.*?(\d\.\d)/);
if (match) {
const rating = parseFloat(match[1] || match[2]);
if (rating < 3.5) { score += 20; signals.push(`Low rating: ${rating}/5`); }
}
}
}
return {company, score, signals: signals.slice(0, 5)};
}
Promise.all(["Competitor A", "Competitor B"].map(scoreLead)).then(leads => {
leads.sort((a, b) => b.score - a.score);
leads.forEach(l => console.log(`${l.company}: score=${l.score}, signals=${l.signals.length}`));
});Platforms Used
Web search with knowledge graph, PAA, and AI overviews