v1.0.0 · Updated 30 July 2026

Documentation

Everything about installing, running and getting results from Ripple Lead Finder. Every number here was read from the shipped source.

Install

Requirement: Python 3.8 or newer. The only dependency is Flask, and the launchers install it for you on first run.

macOSWindows 10 & 11Linux~2 min setup

macOS

  1. Download the release ZIP and unzip it somewhere easy to find, e.g. your Desktop.
  2. Double-click start.command.
  3. First run only: macOS blocks unidentified developers. Right-click the file, choose Open, then Open again. Needed once, ever.
  4. Your browser opens automatically at http://127.0.0.1:5000.

Windows

  1. Download the release ZIP and unzip it to your Desktop.
  2. Double-click start.bat.
  3. If Python isn't installed, get it from python.org and tick "Add python.exe to PATH" on the installer's first screen.
  4. Your browser opens automatically at http://127.0.0.1:5000.
The single most common Windows failure. If start.bat flashes and closes, Python isn't on your PATH. Reinstall Python and tick that checkbox on the first screen.

Any platform, from a terminal

$ git clone https://github.com/RippleCheck/Lead-Finder.git
$ cd Lead-Finder
$ pip3 install flask
$ python3 app.py

Leave the launcher window open while you use the app — closing it stops the server.

macOS port clash. AirPlay Receiver occupies port 5000. If the page won't load, turn it off in System Settings → General → AirDrop & Handoff, or change the port at the bottom of app.py.

Quick start

#ActionDetail
1Pick industry108 categories in the dropdown
2Pick country111 options. India is intentionally excluded
3Pick townInstant for 12 seeded countries; fetched once for others, then cached
4Pick modeNo website / dead-bad website / both
5Find Businesses10–40 seconds. The UI stays responsive throughout
6Star the good onesShortlisted leads pin to the top
7Open a leadContact details, verified links, owner name
8Copy a messageSocial DM, cold email, call script or follow-up
9Send it yourselfManually, from your own account
10Mark the stageNew → Contacted → Replied → Won / Lost
Practical tip that beats any feature. Smaller towns convert better than big cities: less competition, and the owner usually answers the phone themselves rather than a receptionist. Try Otley or Ilkley before trying London.

Settings & API keys

Everything is configured in the in-app Settings panel — no terminal, no environment variables, no restart.

SettingEffect
Your nameSigns every message
Portfolio linkAdded to cold emails
TurnaroundQuoted in messages, e.g. "5 days"
AI providerOne-click switch between OpenAI and Anthropic
API keyPasted in, stored in config.json. Never sent back to the browser — the settings endpoint returns only a boolean saying whether a key exists
AI is strictly optional. Every feature works with no key at all. A key only makes each message uniquely worded. If an API call ever fails, the app falls back to the template — you never get an empty box. Leaving a key field blank preserves the previously saved key.

Data sources

SourceUsed forNotes
Overpass APIBusiness dataThree public mirrors with automatic failover
NominatimGeocodingPrimary geocoder
Photon (komoot)Geocoding backupFires automatically if Nominatim is rate-limited
Bundled seedTown dropdown1,154 towns across 12 countries. Instant, works offline
Link checkerVerifying socialsDirect HTTP against the real profile URLs

All five are free and need no API key.

Why OpenStreetMap and not Google scraping

  • Terms of Service. Google's ToS prohibit automated scraping of search results.
  • It doesn't survive real use. Google serves a CAPTCHA after a few dozen automated queries and then blocks the IP. A scraper that passes testing dies on day one.
  • Unstructured. Search HTML changes constantly, so the parser breaks every few weeks.

OpenStreetMap is free forever, legal to reuse under the ODbL licence, globally covered, and — decisively — structured: website, phone, email, contact:instagram and opening_hours are real fields, so "has no website" is an exact filter rather than a guess.

Honest limitation. OSM coverage is thinner than Google's in some regions, and a few businesses have a website that simply isn't tagged. That's why every lead carries a one-click "Google them" link — verify before you pitch.

Search modes

ModeFindsSpeed
No website at allBusinesses with no website tag. Your cleanest pitchFast
Dead / bad websiteSites that are broken, return 4xx/5xx, have no HTTPS, aren't mobile-friendly, are parked placeholders, or still show a copyright year of 2019 or earlier~30s per 60 leads
BothEverything, annotated with why each one qualifiesSlower

Closed-shop filter

A list full of shut businesses destroys your credibility on the first call. Two independent mechanisms prevent it.

Lifecycle tag rejection

Any element with a lifecycle prefix on any key is dropped: disused, abandoned, demolished, razed, removed, closed, was, old, historic. So disused:shop=bakery never reaches your list.

Explicit closure signals

  • disused=yes, abandoned=yes, closed=yes
  • shop=vacant (empty retail unit)
  • any end_date tag
  • opening_hours=closed or off
Tested edge case. A business tagged old_name (renamed but trading) or historic=yes (heritage building, still open) is deliberately kept. Only the lifecycle-prefix form and explicit closure flags reject.

Lead scoring

The score answers one question: how easily can I reach this person today? It is not a quality or wealth estimate.

SignalPointsWhy
Has phone+40You can cold call today
Has email+30You can cold email today
Has any social handle+15You can at least DM them
Verified-live link+10Channel confirmed reachable
Opening hours tagged+10Actively maintained listing
Data verified 2024-07 or later+10Recently confirmed to exist
Data verified 2022-07 to 2024-06+5Reasonably recent
Owner name known+5Open with a real name
Street address present+5Real premises, not a ghost listing

Worked example. A barber with phone, email, address, opening hours, a known operator and a check date of 2026-04 scores 40 + 30 + 5 + 10 + 5 + 10 = 100. A social-only listing scores 15. Both are real leads; the first is worth your morning.

Social links in map data are often stale. During a search the top 50 leads' Instagram, Facebook and website links are checked live, twelve at a time.

ResultTriggerMeaning
LiveHTTP 200–399Safe to open and DM. Adds +10 score
BrokenHTTP 404, 410, 5xxDead handle. Don't waste time
Unmarked401, 403, 429, timeoutPlatform blocked the checker. Not evidence it's dead
Why the third state exists. Instagram and Facebook aggressively bot-block automated requests. Treating "blocked" as "broken" would mark perfectly good leads as dead and quietly waste the best half of your list. When in doubt, the app says nothing rather than something false.

When a handle is missing entirely, each lead offers one-click targeted searches: Find their Instagram, Find their Facebook, Google them and Google Maps, plus a link to the source OSM listing so you can audit the data.

Messages

Four types are generated per lead, personalised from that lead's real data, each with a copy button.

TypeLengthContains
Social DM~90 wordsPlatform-neutral wording, so the same text works on Instagram or Facebook
Cold email~150 wordsSubject line, portfolio link, working opt-out
Call script~350 wordsOpener, offer, low-commitment ask, plus six scripted objection responses
Follow-up~50 wordsOne gentle nudge with an explicit easy exit

Objection handling in the call script

They sayYou say
"I'm too busy right now"That's exactly why I do the mockup first — it takes zero time from you. What's the best email?
"Facebook works fine for us"It does, for people already following you. The gap is people googling your trade plus your town — right now they find your competitors.
"How much again?"Flat fee, one payment, no subscription to me.
"My nephew was going to do one"Fair enough. The offer stays open — can I send the free mockup anyway so you've got something to compare?
"Send me some information"Will do — what's the best email? You'll have a mockup in a couple of days, not just a brochure.
"We're not interested"No problem at all, thanks for being straight with me. [Do not push. Mark Lost. Move on.]

Currency by market

Quoting dollars to a UK barber signals you don't know their market, so prices adapt automatically across 12 zones.

MarketPriceMarketPrice
United Kingdom£199AustraliaA$380
Eurozone (IE, DE, FR, ES, IT, NL, PT, AT)€230New ZealandNZ$400
United States$250CanadaC$340
Everywhere else (fallback)$250

Fifteen niche-specific pitch angles name a concrete pain and a concrete win per trade — hotels get "guests book through sites taking 15–20% commission", barbers get "walk-ins can't check prices before turning up" — so the message never reads generic.

Business brief

One click produces a full brief on the business that ends with a paste-ready prompt for any AI website builder. Find lead → copy brief → paste into an AI → deliver site.

ModeNeeds a keyWhat it does
Quick briefNoInstant, offline. Structured from all known map data: identity, contact channels, presence gap, and a complete website build prompt with their real details filled in
AI briefYesEverything above, plus it fetches their current website's text and has your chosen model write richer copy, infer likely services, and give style direction fitting the trade

Guardrails in the AI prompt: only stated facts may be used, unknowns must be marked unknown, no claiming to have visited the premises, no invented reviews or awards, no hype vocabulary.

Pipeline & export

  • Shortlist. Star leads you intend to message. They pin to the top and are counted in the floating outreach panel.
  • Stages. New → Contacted → Replied → Won / Lost, plus private notes per lead.
  • Filters. Industry, country, stage, has phone, has email, has Instagram, has Facebook, verified-live social, owner known, fresh data only, shortlist only.
  • CSV export. Every field including link-verification status and owner name.
  • Persistence. Everything lives in a local leads.db. Re-running the same search never wipes your pipeline — existing leads are skipped, only new ones are added.

Responsible outreach

These rules protect your business, not just theirs.

RuleWhy it protects you
20–30 emails/day from a fresh domainBlasting hundreds on day one gets the domain permanently flagged as spam. Domain reputation cannot be un-burned
Use a separate sending domainNever risk your main address's deliverability
Real sender name, reply-to, opt-outRequired by the US CAN-SPAM Act and expected in most markets. The templates include a "reply STOP" line — leave it in
Honour opt-outs immediatelyOne ignored opt-out can cost you a domain
Treat Canada separatelyCASL generally requires consent before a commercial email, with a narrower B2B exemption than the US, UK or Australia. Start with UK, US and Australia
Never push after a clear noThe call script ends politely on purpose. Your time is better spent on the next lead

API endpoints

The app is a local Flask server. Useful if you want to script against it.

MethodEndpointPurpose
GET/Serves the dashboard
GET/api/healthLiveness probe
GET/api/niches108 categories + whether an AI key is set
GET/api/citiesTown list. Returns source: seed | cache | live
POST/api/searchMain search. Body: niche, place, mode, limit
GET/api/leadsSaved leads, stage counts, facets. Filters: niche, country, stage, starred, q
PATCH/api/lead/<id>Update stage, notes, phone, email, starred
DELETE/api/lead/<id>Remove a lead
POST/api/messageGenerate a message. Body: id, kind, ai
POST/api/briefBusiness brief. Body: id, ai
GET/api/settingsCurrent settings. Never returns raw keys
POST/api/settingsSave settings
GET/api/export.csvFull CSV export

The engine also runs standalone from the command line:

$ python3 engine.py "Bakery" "Porto, Portugal"
$ python3 engine.py "Dentist" "Warsaw, Poland"

Files & privacy

FilePurpose
app.pyLocal server, 13 endpoints, SQLite schema and migrations
engine.pyGeocoding, Overpass queries, closed-shop filter, link verification, scoring
messages.pyMessage templates, currency zones, business brief, optional AI
dashboard.htmlThe entire UI. One file, no build step
cities_seed.json1,154 bundled towns
leads.dbCreated on first run. Your leads and pipeline. Back this up
config.jsonCreated on first Settings save. Holds your API key
If you fork this repo, never commit leads.db or config.json. The first contains real people's phone numbers and email addresses; the second contains your billable API key. Both are gitignored by default — keep it that way.

Privacy. Everything runs locally. The only outbound calls are to OpenStreetMap for business data and, only if you add a key, to your chosen AI provider. No telemetry, no accounts, no analytics.

Troubleshooting

SymptomFix
Page won't load on macOSAirPlay Receiver holds port 5000. Turn it off in System Settings → General → AirDrop & Handoff, or change the port in app.py
start.bat does nothingPython isn't on PATH. Reinstall and tick "Add python.exe to PATH"
macOS "unidentified developer"Right-click start.command → Open → Open. Once only
"All OpenStreetMap mirrors were busy"Public mirrors rate-limit at peak times. Wait a minute and retry — the app already tries three
"Couldn't find [town]"Use the dropdown, or type the fuller form: "Leeds, United Kingdom"
Zero resultsThin OSM coverage for that trade there. Try a bigger town, a commoner trade, or switch mode to Both
Search feels slow"Dead / bad website" mode makes one live HTTP request per business. ~30s for 60 leads is expected
AI rewrite button disabledNo key saved for the selected provider. Settings → paste a key

License

Ripple Lead Finder is released under the MIT License, Copyright © 2026 Agrajeet Verma. You may use, modify, distribute and sell it, with attribution.

Two licences apply. MIT covers the code. The business data comes from OpenStreetMap under the ODbL licence, which legally requires attribution to OpenStreetMap contributors. If you fork or redistribute this, keep that credit — it's an obligation, not a courtesy.

Questions or bugs: open an issue on GitHub or email team@ripplecheck.io.