Skip to content
← All the work

Case 01Lead RadarAutomation · Intelligence · ApplicationsIn use · 2026

Finding businesses worth approaching was taking too much manual work.

A lead pipeline that splits a search into areas, reads each business's own website for a way to reach it, and stops at the decision to contact anyone - which stays mine.

leads in two days, when a country was one query
~16
duplicates from re-running the same queries
954
leads with no email that now have one
10 of 12
pipeline tests passing
75 / 75

01 Problem

The problem

To approach a business I had to find it, open its website, judge whether the site was a problem I could fix, find a way to reach the owner, and decide whether it was worth it at all. Every lead was five small jobs, done by hand, one tab at a time.

The plan I was working to asked for ten qualified leads a day, feeding five previews and ten to fifteen messages. Done by hand, the finding was the bottleneck, not the writing.

02 Evidence

How I knew it was real

  • The arithmetic, written down before anything was automated: ten qualified leads a day, feeding five previews and ten to fifteen outreach messages.
  • Judging a website by rule was worse than judging it by eye. The first automated check flagged sites as weak that turned out to be high quality, and I dropped the quality rules the same day.
  • The provider's own data was wrong too. Of 53 businesses listed as having no website, a search check found sites for 9.
  • The first version's four runs produced 198 rows and not one email address. Two months later the gap was still there: of 351 accepted leads, 51 had an email, because nothing ever opened the business's own site.

03 Decision

What I set out to change

Turn finding into a repeatable system that shows its evidence for every business - and keep the decision to contact anyone human.

What I deliberately left alone

  • Writing to anyone. Nothing is sent from a lead; contacting them is mine, by hand, outside the system.
  • Guessing email addresses. It reads the ones a business publishes on its own site. A guessed address is a claim about a business I have not checked.
  • Paid lookups by default. A configured key is not consent to spend, and a source whose cost is unknown counts as paid.

The choices worth arguing with

  1. Chose One search per area, so a country becomes many small searches that can each fail on their own.

    Over One search for the whole country - which the provider answered with its twenty most prominent businesses, all of which already had websites.

    Because The businesses I can help are exactly the ones a prominence-ranked list leaves out.

  2. Chose The app decides what to search for; the worker only runs it.

    Over Letting the n8n worker map categories itself. It understood 4 of 73, and for the rest it found nothing and reported success.

    Because A search that cannot match and a town with no salons looked identical from the outside.

  3. Chose A batch from a source nobody approved is refused whole.

    Over Filtering out the bad rows, or hiding them.

    Because Both hide that it happened - and the next thing to go wrong would hide the same way.

  4. Chose Only an email found on the business's own site counts, rated by where on the site it was found.

    Over Pattern-guessing addresses, or paying a lookup service.

    Because Free first, and never invented - the same rule I hold every pitch to.

04 Build

What I built

A search starts as a category, a place and a purpose: which offer it is for, and whether it may spend money. A planner turns a country into a tiered list of cities and a category into a set of fingerprinted queries, and a gate separates the sources that can actually run from the ones that are only a way of looking.

Each area goes out as its own signed request to a worker in n8n, which queries OpenStreetMap - or Google Places, only when paid search was explicitly allowed - and sends the results back. The app checks the signature and the sources, qualifies and scores each business, and stores it once, keyed on the business rather than on the row.

Every new lead's own website is then read for a way to reach it: four pages at most, nine seconds a page, and every email rated by where it was found. Then it waits for me.

  1. SourceA searchCategory, place, which offer it is for, and whether it may spend.
  2. StepPlanA country becomes tiered cities; a category becomes fingerprinted queries.
  3. StepExecution gateOnly sources that can run. Paid ones only with an explicit yes.
  4. StepOne request per areaEach one signed, and each able to fail alone.
  5. Sourcen8n workerOpenStreetMap per area; Google Places only if approved.
  6. StepCallback boundaryChecks signature and sources. A violation refuses the whole batch.
  7. KeptOne record per businessQualified, scored, and stored once - keyed on the business.
  8. StepRead their own siteFour pages at most. Each email rated by where it was found.
  9. A personKeep or skipMine, recorded with who decided and when.
  10. OutContact, by handOutside the system. Nothing is sent from a lead.
Everything before the bronze step finds, checks and refuses. The only arrow into a contact comes from me.

05 Validation

How I tried to break it

  • A whole country searched as one query

    Now 25 places, around seventy trades with local-language synonyms, and a planner that crosses place, trade, synonym and source into separate queries.

    Broke, then fixed · July 2026

  • The same query run again and again

    Queries already run are skipped by fingerprint. Before the fix, 200 calls were only 5 distinct queries, and they produced 954 duplicates.

    Broke, then fixed · July 2026

  • One city times out

    Each area is its own request, so a timeout costs that area. Before, a timeout in one city returned zero for the whole country.

    Broke, then fixed · 10 Sep 2026

  • A category the worker does not understand

    Refused before anything runs, instead of finding nothing and reporting success.

    Broke, then fixed · 10 Sep 2026

  • A worker that widens its own list of sources

    The callback fails closed and refuses the whole batch.

    Broke, then fixed · 31 Aug 2026

  • A slow or hostile website during enrichment

    One slow site cannot stall the batch, and an unreachable one never un-accepts a lead.

    Held

  • No email published anywhere

    Recorded as not found. Nothing is guessed.

    Held

What did not work

  • The first version judged website quality from the markup and was wrong about the sites it called weak. I dropped the rules the same day: reliable judgement of a site from its HTML was not feasible, and precision mattered more than recall.
  • In July a version produced about sixteen leads in two days. Nothing in the pipeline was broken - the question it asked was unanswerable, because a whole country was one query.
  • In August a geography check rejected all 283 results of a run. After the fix, 277 were accepted.

06 Outcome

What changed

~16 leads in two days, when a country was one query
Stated in the commit that redesigned the search, 2026-07-22, as the result it replaced.
954 duplicates from re-running the same queries
Counted when the fingerprint check was fixed in July 2026.
10 of 12 leads with no email that now have one
One search on 2026-09-11, after every new lead's own site started being read.
75 / 75 pipeline tests passing
Five test files for search, planning, execution, email and enrichment, run on 2026-09-11.

Finding is a system now. A search becomes area-by-area queries, every business arrives once with the evidence for why it qualified, and its own site has already been read for a way to reach it.

What it has not done yet is prove money. Contacts, replies and clients won are not tracked from a lead, so I can tell you how many businesses it finds and how many it can reach - and nothing yet about how many became work.

What I measure next

  • Duplicate rateBatch size against distinct business keys per run. Today found, unique and stored are one number.
  • Area success across runsThe per-area counters each run already writes, added up over a month.
  • Reach after enrichmentThe share of new leads with a high-confidence email, from the enrichment counters.
  • What a lead turns intoKeep or skip, then contacted, replied and won - the last three need outreach joined to the lead.

07 Learning

What I learned

The same failure came back at three scales: a whole country as one query, six cities as one request, nine sources checked as one list. Each fix was the same move - split the whole into parts that can fail on their own, and make each failure visible.

Most of the work was making zero mean one thing. None found, could not search, timed out and not tried yet all used to print the same zero - and a zero that means four things is a number nobody can act on.

A provider's field is a claim, not a fact. It said nine businesses had no website that did.

What I would change next

  • Count duplicates at the boundary, so the dedupe can be shown working rather than asserted.
  • Make a re-sent batch provably unable to touch a lead I have already reviewed.
  • Join leads to outreach, so found can finally be followed through to won.
Lead Radar: how I built it - Eva Jereb