Case study · Local Market Intelligence

Knowing which local businesses to call first.

Pick a town. Get back every business in it, each one scored on how strong it is, how weak its web presence is, and how close it sits to your door, so the best leads float to the top of a single ranked list. Here's how I built it, using my own backyard on the South Shore as the guinea pig.

OpenStreetMap · Google Places · BigQuery · OSRM · Python · Cloudflare

01

The problem with a phone book

Prospecting · Targeting · Where to start

"A list of 450 businesses isn't really a lead list, it's a wall of names. The actual work is figuring out which 20 of them are worth calling on Monday morning."

Truth be told, anybody who sells to local businesses runs into the same wall. You've got hundreds of shops, restaurants, contractors, and offices within a short drive, and no good way to tell which ones are actually worth a conversation. So outreach ends up driven by whoever you happened to notice last week, or an alphabetical list you lose patience with somewhere around the letter C.

The useful signal is buried in there, but it's real. A business with great reviews and a steady stream of customers, that still has no website and barely shows up on social, is a wildly different prospect from a slick operation with a full marketing team already humming. The first one has proven demand and a visible gap you can help with. The second one is doing just fine without you. The whole trick is measuring that difference across every business at once, instead of one gut feeling at a time.

So I built GeoOutbound to do exactly that, and pointed it at the five towns around Scituate for the first run, because I figured I'd start with the backyard I actually know. What comes out the other side is a single dashboard where the highest-opportunity businesses sort straight to the top, each one with a phone number already attached.

Before

Outreach driven by memory and chance. No way to compare one prospect to another. The businesses that most need help are invisible inside a flat list of names.

After

Every business in range scored 0 to 100 on a consistent opportunity model, ranked, filterable by town and web status, with contact details on every row.

447
businesses discovered and enriched across five towns
99
scored as hot leads (70+) and ranked for outreach
114
with no working website at all - the core opportunity
1
ranked list replacing a wall of undifferentiated names
02

Finding everyone, then proving who is real

Discovery · Enrichment · Data Quality

Discovery starts with OpenStreetMap, which catalogs businesses by location for free, which is exactly the price I like to start at. For each town the pipeline pulls every named shop, office, and service, then works out two distances from the seed address: a straight-line distance and a real driving time routed through OSRM. Proximity feeds the score, so I wanted a measured drive time, not a rough "eh, that's about ten minutes" guess.

Now, OpenStreetMap has a blind spot worth being honest about. It misses a fair number of small businesses, and its town-name matching is loose enough that a "Hingham" in Montana and a "Marshfield" in Missouri both tried to sneak into my South Shore dataset. A hard geographic boundary check tosses those out, and then Google Places fills the coverage gaps and confirms which businesses are actually open for business.

That Google layer is where the dataset really earns its trust. Each business gets matched to its Google Maps listing, which hands back a star rating and a review count. A bakery sitting at 4.9 stars with 152 reviews isn't a guess about demand, it's a measurement of it, and that rating becomes the backbone of the whole opportunity score. It's what separates a thriving business with a presence gap (a great lead) from a quiet one that simply has no customers to lose (not your problem to solve).

Before

No single source covers every local business cleanly. Free data is incomplete and noisy; paid data is expensive to use blindly.

After

A free-first pipeline that discovers broadly, filters out geographic noise, and spends on Google only where it adds the rating signal the score depends on.

5
towns swept: Scituate, Cohasset, Hingham, Norwell, Marshfield
~$0
monthly data cost at this volume, inside free API tiers
246
out-of-region false matches caught and rejected by the boundary check
2
distance measures per business: straight-line and real drive time

OpenStreetMap Overpass · OSRM routing · Google Places API · bounding-box validation · Python httpx

03

Scoring the gap as well as the business

Opportunity Model · Web Presence · Ranking

"High on the list is an auto repair shop. Almost five stars, dozens of reviews, no website at all, and seventeen hundred feet from my front door. That right there is the whole product in a single row."

For every business, the pipeline checks whether a website even exists, and if it does, it scores the quality out of ten on plain, explainable stuff: does it load, is it secure, is it mobile-ready, does it carry real contact details, is it more than a parked placeholder somebody forgot about. Then it goes looking for the business across Facebook, Instagram, Bluesky, and X, and grabs whatever contact details are public along the way, phone, email, address, the works.

All of that rolls up into one opportunity score from 0 to 100. It rewards proven demand, pulled from the Google rating and review count. It rewards a presence gap, so a business with no site scores higher than one that already has a polished one. And it rewards proximity, decaying as the drive time grows, because a great lead an hour away is a worse lead than a good one down the street. Every score keeps its component breakdown attached, so I can always explain a ranking instead of asking anyone to take it on faith.

The output is a private, password-protected dashboard. Sort by score and the best targets are already sitting on top. Filter to a single town, or just to businesses with no website at all, and the list reshapes itself instantly. Every row carries a phone number, so the distance between deciding who to call and actually calling them is exactly one click.

Before

Web presence judged one business at a time, by eye, with no way to weigh it against demand or distance.

After

A single transparent score blending demand, web gap, social gap, and proximity, with the math shown for every business on the list.

0-100
opportunity score, with a stored breakdown for every business
10
point website-quality check on explainable criteria
4
social platforms checked per business
2,030
contact details harvested: addresses, phones, and emails

BigQuery SQL scoring · website quality heuristics · social + listings detection · Cloudflare Pages (gated dashboard)

Behind it all

A pipeline that points at any town

Architecture · Reusability · What this becomes

The geography lives in a config setting instead of being buried somewhere in the code. Change the seed address and the town list, re-run the pipeline, and the same discovery, enrichment, and scoring all run against a brand new market. The South Shore was just the proving ground. The machine itself goes wherever you point it.

Every stage writes to Google BigQuery, so the whole dataset stays queryable, auditable, and cheap to keep around. The data model already has room to grow: the same pool of scored businesses can be re-ranked against different criteria as the questions change, without me rebuilding the foundation every time. It started life as a prospecting tool, but truth be told, what I actually built is a local market intelligence engine that just happens to point at lead generation first.

5
pipeline stages from raw map data to ranked dashboard
Config
geography is a parameter - retarget by changing two settings
Free
first by design - paid APIs only where they add signal
Extensible
built to score the same businesses for future offerings

Python · Google BigQuery · OpenStreetMap · OSRM · Google Places · Cloudflare Pages + Functions

If you sell to local businesses, you've got this problem too.

The gap between a list of names and a ranked list of the right names is where most outreach quietly stalls out. I'm happy to build this engine pointed at your market, your criteria, and your front door. Let's have a chat.