You add one line to a Google Sheet something like dental clinics in Dubai. Everything after that happens on its own.
It finds those businesses on Google Maps, opens each one’s website and reads it, scores every business out of 10, writes a personalised HTML email to the good ones, sends it, and logs the result. Businesses with no email but a valid phone number get filed separately for a call instead of being silently dropped.
Sharing the whole build here, including the parts that didn’t work first time.
How it finds the leads
Google Sheets — Watch Rows watches a locations sheet and picks up new rows, two per cycle. Whatever sits in column A becomes the search query.
SerpApi — Search Google Maps runs that search and returns local businesses with name, category, address, phone, website, rating and review count.
Iterator splits local_results so every business becomes its own bundle. Everything after this point runs once per business — this is the step that turns one search into twenty leads, and it’s the one people forget.
How it researches them
Apify — Scrape Single URL opens {{11.website}} with the stealthy Firefox crawler and returns the page text. This is what lifts the quality of the scoring. A Google Maps listing tells you a business exists; the website tells you what they actually do and whether they’d care about what you sell.
How it decides and reaches out
This is the part worth talking about, because I built it twice.
Version 1 looked like most tutorials: two AI Tools > Ask modules, two AI Tools > Extract modules to pull clean fields back out of the AI’s text, a router, and filters on every branch. Roughly ten modules doing the thinking.
Version 2 is one AI Agent with a defined response structure and three tools.
The response structure — four fields, so Make maps them straight out with no Extract step:
score number 1–10
contact_email a real email, or NONE
email_subject the subject line
email_body email-safe HTML
Its three tools:
- Send qualified email → Gmail, body type Raw HTML
- Log emailed lead → Google Sheets,
Emails - Save phone lead → Google Sheets,
Lead with phone
Its rules, written as plain sentences in the instructions rather than as filter conditions:
- Score 7+ and an email → send, then log
- Score 7+, no email, has phone → save the phone lead
- Score below 7, or no usable contact → call nothing
- Never call both lead paths for the same business
What actually caused me trouble
Vague tool descriptions mean skipped tool calls. My first description for the email tool explained what it did. The agent kept not calling it. Rewriting it to describe when to use it — “when the business has a valid email address and the score is 7 or higher” — fixed it immediately. Describe the situation that triggers the tool, not the action it performs.
The agent will invent an email if you let it. Adding “never invent one, return NONE when no email is visible” to the instructions wasn’t optional. Without it I got plausible-looking info@ addresses that didn’t exist.
Gmail body type has to be Raw HTML. Otherwise the styled CTA link arrives as visible HTML source in the recipient’s inbox. Obvious in hindsight, twenty minutes gone.
Watch the trigger limit while testing. Two rows per cycle with an iterator behind it is already up to ~40 businesses per run, each with a website scrape and an agent call. Keep it low until you’re happy with the output.
Scraping is the slow part. The stealthy Firefox crawler is reliable but not quick. Worth knowing before you sit watching a run.
Honest trade-offs of going agent-first
Better: far fewer modules, rules that read as English, and adding a new action means adding a tool instead of rewiring branches.
Worse: the agent can silently skip a tool call, it’s harder to debug than a filter whose value you can inspect, and it costs more tokens per business.
My takeaway use an agent where the decision is genuinely a judgement call, and keep a filter where the rule is exact and has to hold every single time. Scoring a business is judgement. “Does this string contain an @” is not.
Two things I’m still figuring out
Verifying a tool call actually happened. If the agent decides not to call the logging tool, nothing tells me. Is anyone adding a fallback module after the agent to catch runs where no tool fired?
Enforcing order between tool calls. Send-then-log works, but I’d like more confidence that “then” is guaranteed rather than usually-true. Has anyone found a reliable pattern for this?
The blueprint
Here’s the full scenario if you want to pull it apart or build on it:
Open it while signed in to Make and clone it into your own account. Connections never transfer with a shared scenario, so you’ll need to reconnect every module to your own accounts and repoint the Google Sheets modules at your own spreadsheet. The sheets it expects are locations, Emails and Lead with phone.
Happy to answer questions on any part of it.
