Data provided by AnyAPI. AnyAPI supplies the Google Maps, website, review, contact-enrichment, and Google Search data used throughout the workflow.
An n8n workflow that finds local businesses to sell to, and gives you a specific, provable reason to call each one.
The current workflow is
local-lead-machine-agent.workflow.json. It discovers
100+ local businesses, requires repeated review evidence for the problem you solve, and then sends
only qualified businesses through a second agent for contact and company research.
One measured end-to-end n8n run screened 120 businesses, found 14 evidence-qualified prospects, and delivered 12 usable leads by email plus a professional Excel lead board. The run found 6 email addresses, 11 phone numbers, and 8 official contact pages for $0.42448 in AnyAPI data.
See LATEST.md for setup, Data Table schemas, the measured run, and API calls.
If you came from the Reddit post, import the current workflow:
local-lead-machine-agent.workflow.json. The other two
JSON files are earlier versions kept for reference:
| Workflow | Status | What it does |
|---|---|---|
local-lead-machine-agent.workflow.json |
Current | 32-node research pipeline with evidence qualification, contact enrichment, email, and Excel delivery |
local-lead-machine-pro.workflow.json |
Legacy | 26-node website and review audit with an LLM-generated opener |
local-lead-machine.workflow.json |
Legacy lite | 13-node scheduled website and review audit without an LLM |
Not a lead list. Anyone can pull a list off Google Maps. This opens every prospect's website and reads their worst reviews, then hands you a sentence like:
Every one of your eight worst reviews is unanswered, the most recent is from last month, and there is no analytics on your site.
You type in the kind of local business you want to reach. It costs about two thirds of a cent per qualified lead.
One real run, nail salons across eight cities in the Phoenix metro, 124 businesses for $0.85.
Everything below is measured, not estimated. The raw dataset is in
data/phoenix-nail-salons.json.
| 82% of businesses with 30+ reviews have a negative review the owner never answered | 89/108 |
| 31% have never answered any of their eight worst reviews | 33/108 |
| 27% list no website on their Google profile | 33/124 |
| ...and 9% of those do have one, just not linked to their profile | 3/33 |
| 72% of the sites we could read have no analytics installed | 60/83 |
| 66% have no contact form | 55/83 |
| 59% have no structured data markup | 49/83 |
| 16% have no way to book online | 13/83 |
| 65% scored 40 or higher, i.e. worth a call | 81/124 |
| Only 3% had nothing wrong at all | 4/124 |
Cost breakdown for that run: maps.contacts $0.372, maps.reviews $0.351, web.scrape $0.090,
google.search $0.033.
Selling the list is easy. Qualifying it is where the value is, and it is where the naive version quietly lies to you. Three examples from building this, all caught before shipping:
1. A narrow regex manufactures defects. The first version looked for booking vendors (Calendly, Acuity, Booksy, Vagaro, Mindbody) and reported that 73% of businesses had no online booking. Broadening it to also match booking links and booking calls to action put the real figure at 9%. Almost every business had a booking path; it just was not one of five scripts. A number that wrong survives exactly until the first person opens two of the sites.
2. Source HTML is not the rendered page. We scrape rawHtml. Measured: the same URL at
waitFor: 0 and waitFor: 8000 returns byte-identical HTML, both billed, neither cached. So
anything a tag manager injects at runtime is invisible. Chat widgets and Meta pixels were dropped
as signals entirely, because "missing" was unfalsifiable. Analytics, structured data and forms
stayed, because those live in source.
3. "No website" needs verifying, and the obvious check fails. Google Maps only tells you
whether a website is listed on the profile. Googling the business and taking the first
plausible domain gets it wrong: on 9 test businesses, 4 surfaced a same-name competitor
(phoenixautoshop.com is not "Phoenix Auto Repair & Body Shop"). Matching the phone number on
the candidate page against the Maps listing is what makes it reliable. That check is a stage in
the workflow.
Every claim in the shipped dataset was then re-checked by
scripts/verify.mjs, which re-fetches the evidence and re-asserts each
claim with broader patterns than the pipeline uses, so a bug in the rules cannot hide.
26 claims across 10 leads, 0 false.
Setup, once. A form takes your website URL, the local business type you want to reach, and the cities to cover. An LLM reads your own site to work out what you sell and which defects therefore signal need. You review it before it saves.
- Find them - one
maps.contactscall per city returns up to 20 businesses with phone, website, scraped email, socials, rating and review count. Deduped on place id. $0.003 per business, billed per result. - Split - businesses with no website listed go down their own path, because that is a different pitch.
- Read their site -
web.scrapefor the ones that have one, with a stealth retry when the first fetch hits a bot interstitial. HTML is reduced to booleans immediately and discarded. $0.0005 per site. - Or check whether they really have none -
google.search, then scrape the best non-directory result, then confirm by phone number. - Read their worst reviews -
maps.reviewswithsort: lowestRanking.ownerResponseis an empty string when the owner never replied, so "they ignored this one" is exact rather than inferred. $0.0004 per review. - Score - plain weights in a Code node. Every point traces to a link a human can click.
- Deliver - a Google Sheet with all of it, and an email with the top 10 and one sentence per lead.
- Import
local-lead-machine-pro.workflow.jsoninto n8n (Workflows > Import from File).local-lead-machine.workflow.jsonis a 13-node lite version using only the two most reliable signals and no LLM. - Install the AnyAPI community node: Settings > Community Nodes > install
n8n-nodes-anyapi. Create an AnyAPI API credential with a key from getanyapi.com and select it on every AnyAPI node. That one key covers the Maps lookups, the site scrapes, the Google search and the reviews. - OpenRouter (pro only) - add a credential on the model node. The profiling and opener steps run fine on a fast model.
- Gmail + Google Sheets - connect your Google credentials, set the recipient and the target spreadsheet.
- Run the onboarding form once, then activate the schedule.
The site rules are four regexes in one Code node. Change them.
If what you sell does not map to a website defect - staffing, linen, commercial cleaning, POS,
food distribution - use complaint mining instead. maps.reviews accepts a reviewsFilterString,
so you can search a business's own reviews for the problem you fix:
| You sell | Search their reviews for |
|---|---|
| Staffing | slow, wait, short staffed |
| Linen / uniforms | dirty, stained, sticky |
| POS / payments | cash only, card machine, system down |
| Commercial cleaning | dirty bathroom, smell |
| HVAC service | too hot, freezing, AC |
Measured: a filtered search that finds nothing costs $0.00005, because you are billed per result returned. You can run six phrases per business and only pay on a hit.
-
This finds you a reason to call. It does not find you a customer.
-
Yield varies enormously by vertical. Nail salons and auto repair have three to four times the no-website rate of med spas and plumbers, who are marketing-sophisticated and mostly have competent sites. Do not assume the numbers above transfer. Measured across four Phoenix verticals:
vertical no website site blocked scraper no analytics nail salon 27-33% 5-9% 72% auto repair 25% 44% 40% med spa 7% 21% 9% plumber 8% 9% 20% -
Some sites block scrapers. 9% here, 44% for auto repair. Those get one stealth retry and are then skipped rather than guessed at.
-
The review count is a floor, not a total. We only fetch the 8 lowest-rated reviews, so "every one of their 8 worst is unanswered" means exactly that, not that they have only 8.
-
Businesses under 30 reviews are skipped for the review check. Measured: they have no negatives to find, so the call is pure waste.
-
A 124-business run takes about 15 minutes. It is a weekly job, not an interactive one.
-
web.scrapeoccasionally 502s. Retry is enabled on the nodes. At the time of writing it also rejects thehtml,linksand explicitmarkdownformats, so the workflow asks forrawHtml.
Pay per request in USD, no subscription. The Phoenix run: $0.85 for 124 qualified leads, about $0.0068 each. Model costs depend on your OpenRouter choice.
| Path | What it is |
|---|---|
local-lead-machine-pro.workflow.json |
The full workflow, 26 nodes |
local-lead-machine.workflow.json |
Lite version, 13 nodes, no LLM |
scripts/signals.mjs |
The signal rules. Shared verbatim with the workflow's Code nodes so they cannot drift |
scripts/run.mjs |
Reference pipeline, mirrors the workflow band for band |
scripts/verify.mjs |
Independent re-check of every claim in a dataset |
scripts/recheck-sites.mjs |
Re-measures site signals after a rule change |
data/phoenix-nail-salons.json |
The 124-business run, raw |
MIT