How to find local businesses without a website (Google Maps + Python)
If you build websites for local businesses, the best prospects are easy to describe and annoying to find: a plumber with 200 good reviews and no website, a dentist whose site shows "Account Suspended", a roofer whose sit
If you build websites for local businesses, the best prospects are easy to describe and annoying to find: a plumber with 200 good reviews and no website, a dentist whose site shows "Account Suspended", a roofer whose site still says © 2016 and doesn't work on a phone.
Google Maps lists all of them. Finding them by hand means opening every listing, clicking every website link and judging each site yourself. That's an evening per dozen businesses.
Here is how to do it in one run, with the reason attached to each business.
Disclosure: I build scrapers on Apify, including the Google Maps Scraper used below.
The idea
- Pull every business of a type in a few ZIP codes from Google Maps.
- Open each business's website and check it.
- Keep the ones with a real problem: no website, a site that's down or suspended, no mobile version, no HTTPS, or a copyright notice five or more years old.
The tricky part is step 2. A naive check produces false alarms that would embarrass you in a cold email. Some examples I hit while building it:
- Cloudflare answers HTTP 520 to cloud servers for sites that load fine at home. In one test run, 10 of 10 sites that looked "down" from a server were fine from a home connection.
-
A broken deep link isn't a broken site. Google listings often link to
/contact/?utm_source=.... That page can 404 while the homepage works. - "© 2015" in the page source can come from a CSS library's license comment (animate.css has one), not from the site's footer.
- One site that sends bytes forever can stall a whole scraper if every read doesn't have a hard deadline.
So the rules are strict. A site counts as down only after two failed tries and only if its homepage fails too. Bot walls and 520s are "unknown" and never claimed. Copyright years are read from the visible page only.
Running it
I'll use the Google Maps Scraper on Apify. No Google API key.
pip install apify-client
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("scrape-lads/google-maps-scraper").call(run_input={
"searchTerms": ["plumber", "roofing contractor"],
"locations": ["75201", "75204", "75206", "75214"], # Dallas ZIP codes
"websiteFilter": "needsWork", # only businesses that need website work
"scrapeContacts": True, # emails from the business's own site
"minReviews": 10, # skip brand-new listings
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
print(row["name"], row.get("phone"), row["websiteStatus"], row["websiteIssues"])
websiteFilter: "needsWork" switches the website check on by itself. Each row comes back like this (made-up business, real shape):
{
"name": "Prairie Roof Co.",
"category": "Roofing contractor",
"phone": "(214) 555-0163",
"rating": 4.7,
"reviewCount": 88,
"website": "http://prairieroof.example/",
"emails": [],
"websiteStatus": "down",
"websiteIssues": ["website is down: domain does not resolve"],
"needsWebsiteWork": true
}
websiteStatus is one of ok, down, no-website or unknown. For ok sites, websiteIssues lists what's wrong: no HTTPS, no viewport tag, old copyright year, no contact form, no tap-to-call link, built with Wix or GoDaddy.
What a real run looks like
I ran 400 places (roofing and HVAC contractors in Dallas and Phoenix):
- 57 places (14%) needed website work
- 34 had no website at all
- 5 had a site that was down: four dead domains and one "Database Error" page, all confirmed by hand afterwards
- 18 had a working site with a strong problem, mostly an old copyright year or no HTTPS
So expect roughly 5 to 15% of a search to qualify. Google Maps returns about 120 to 200 places per search, so use several ZIP codes and two or three related business types to build a decent list.
Turning it into outreach
The reason is the opener. "Your website link on Google shows Account Suspended" gets a reply. "Do you need a new website?" doesn't.
A few practical notes:
- Businesses with no website usually have no email (there's no site to find one on). Call them, or find their Facebook page.
-
emailsonly holds addresses on the business's own domain, or that clearly belong to it. Site footers often carry the web designer's address or a template placeholder, and those are dropped. - Cold outreach is regulated: CAN-SPAM in the US, GDPR in Europe. Keep it relevant and personal.
Cost
Pay per result: $1 per 1,000 places, plus $1 per 1,000 websites checked and $1 per 1,000 places with an email. Places the filter removes and sites it couldn't check are free. A list of 1,000 businesses that need website work costs about $2, and the Apify free plan's monthly credit covers a first test.
There's also a step-by-step guide with a ready-made input you can paste.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.