Google Maps Lead Scraper: How to Build a Local B2B Outreach List with CoreClaw
The fastest way to build a local B2B outreach list is to turn Google Maps business listings into structured, filterable records. A Google Maps lead scraper extracts public business names, addresses, phone numbers, websites, categories, ratings, and review counts, then lets you score and load the results into a CRM or outreach tool. This guide is for sales teams, local SEO agencies, and SaaS founders who need a repeatable Python workflow for collecting and qualifying local leads without maintaining their own scraping infrastructure.
TL;DR
- A Google Maps lead scraper reads public business listings and returns structured fields you can filter by category, rating, and location.
- Use a managed scraper like the CoreClaw Google Maps Scraper to skip proxy rotation, browser management, and anti-bot maintenance.
- A short Python script normalizes the output, deduplicates by phone or website, scores leads by review signals, and exports a CSV ready for a CRM or cold-outreach tool.
- Always collect only public data, respect Google Maps terms of service, and comply with local privacy and telemarketing rules.
Why Manual Local Lead Research Fails
Building a local lead list by hand is straightforward for five businesses and painful for five hundred. You open Google Maps, search for a category and city, click each listing, copy the name, guess the email, paste the phone number into a spreadsheet, and repeat. Within an hour the spreadsheet is full of inconsistent fields, missing websites, and duplicate chain locations.
The problems multiply quickly:
- Scale. A single city can contain thousands of businesses in one category. Manual collection becomes a multi-day task.
- Freshness. Phone numbers, hours, and websites change. A spreadsheet copied last quarter already contains stale records.
- Deduplication. The same business can appear under slightly different names or addresses. Without a canonical identifier, your list fills with duplicates.
- Qualification. A raw list tells you a business exists; it does not tell you which ones are worth calling first. You need signals like rating, review count, category, and web presence to prioritize.
- Provenance. When a record is wrong, you need to know where it came from and when it was collected. Manual copy-paste loses that trail.
A structured scraping workflow solves these problems by producing timestamped, normalized records you can filter, score, and reload on a schedule.
What a Google Maps Lead Scraper Returns
A lead scraper does not invent contact information. It collects the fields that are publicly visible on a Google Maps listing and organizes them into a consistent schema. Typical output fields include:
| Field | Why it matters for outreach |
|---|---|
business_name |
The public trading name of the business. |
address |
Full street address for geo-targeting and routing. |
phone |
Direct public phone number; the best deduplication key. |
website |
Domain for email discovery and enrichment. |
category |
Primary business category for segmentation. |
rating |
Average public review score; a quality signal. |
review_count |
Volume of public reviews; indicates visibility and engagement. |
hours |
Operating hours for call-timing decisions. |
plus_code / place_id
|
Stable identifiers for deduplication and re-scraping. |
collected_at |
Timestamp so you know how fresh the record is. |
The exact field names depend on the scraper you use. The important part is that the output is machine-readable, not a copy-paste mess.
A Runnable Python Lead Qualification Workflow
The script below assumes you have already run a Google Maps scraper and have a JSONL file of raw records, or you are calling a managed worker endpoint that returns structured JSON. It reads configuration from environment variables, normalizes the records, scores each lead, deduplicates by phone or website, and writes a CSV ready for import into a CRM.
import csv
import json
import os
from datetime import datetime, timezone
from urllib.parse import urlparse
# Read endpoint and credentials from environment variables.
# Never hard-code API keys or worker URLs in source control.
CORECLAW_API_KEY = os.environ.get("CORECLAW_API_KEY")
CORECLAW_WORKER_ENDPOINT = os.environ.get("CORECLAW_WORKER_ENDPOINT", "")
INPUT_FILE = os.environ.get("LEAD_INPUT_FILE", "google_maps_raw.jsonl")
OUTPUT_FILE = os.environ.get("LEAD_OUTPUT_FILE", "qualified_leads.csv")
# Outreach targets: edit these to match your ideal customer profile.
TARGET_CATEGORIES = {"marketing agency", "software company", "it services", "consultant"}
MIN_RATING = 3.5
MIN_REVIEW_COUNT = 5
def normalize_record(raw: dict) -> dict:
"""Flatten a raw Google Maps record into a consistent lead schema."""
website = raw.get("website") or raw.get("site") or ""
domain = ""
if website:
parsed = urlparse(website if website.startswith("http") else f"https://{website}")
domain = parsed.netloc.replace("www.", "")
phone = raw.get("phone") or raw.get("phone_number") or ""
if phone:
phone = "".join(c for c in phone if c.isdigit() or c == "+")
return {
"business_name": (raw.get("name") or raw.get("business_name") or "").strip(),
"address": (raw.get("address") or "").strip(),
"phone": phone,
"website": website,
"domain": domain,
"category": (raw.get("category") or "").lower().strip(),
"rating": _to_float(raw.get("rating")),
"review_count": _to_int(raw.get("review_count") or raw.get("reviews")),
"place_id": raw.get("place_id") or raw.get("plus_code") or "",
"collected_at": datetime.now(timezone.utc).isoformat(),
}
def _to_float(value):
try:
return float(value)
except (TypeError, ValueError):
return None
def _to_int(value):
try:
return int(str(value).replace(",", "").replace("+", ""))
except (TypeError, ValueError):
return 0
def score_lead(lead: dict) -> int:
"""Score a lead based on public signals. Higher is better."""
score = 0
if lead["category"] in TARGET_CATEGORIES:
score += 30
if lead["rating"] and lead["rating"] >= MIN_RATING:
score += 20
if lead["review_count"] and lead["review_count"] >= MIN_REVIEW_COUNT:
score += min(lead["review_count"] // 10, 20)
if lead["website"]:
score += 15
if lead["phone"]:
score += 10
return score
def load_records(path: str) -> list:
records = []
with open(path, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
records.append(json.loads(line))
return records
def main() -> None:
raw_records = load_records(INPUT_FILE)
leads = [normalize_record(r) for r in raw_records]
# Score and filter.
qualified = []
for lead in leads:
lead["lead_score"] = score_lead(lead)
if lead["lead_score"] >= 30:
qualified.append(lead)
# Deduplicate by phone, then by domain, then by place_id.
seen: set = set()
unique = []
for lead in qualified:
key = lead["phone"] or lead["domain"] or lead["place_id"]
if not key or key in seen:
continue
seen.add(key)
unique.append(lead)
# Sort by score descending.
unique.sort(key=lambda x: x["lead_score"], reverse=True)
fieldnames = [
"business_name", "category", "rating", "review_count",
"phone", "website", "domain", "address", "lead_score", "collected_at",
]
with open(OUTPUT_FILE, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for lead in unique:
writer.writerow({k: lead.get(k, "") for k in fieldnames})
print(f"Raw records: {len(raw_records)}")
print(f"Qualified leads: {len(unique)}")
print(f"Output written to: {OUTPUT_FILE}")
if __name__ == "__main__":
main()
If you are calling a live worker instead of reading a local file, replace load_records with an authenticated request to your verified endpoint. Keep the endpoint, API key, and output schema in environment variables so the script stays portable.
Representative Output and Checklist
A qualified lead row looks like this:
business_name,category,rating,review_count,phone,website,domain,address,lead_score,collected_at
Acme Digital,marketing agency,4.7,42,+15551234567,https://acmedigital.com,acmedigital.com,"123 Main St, Austin, TX",95,2026-09-19T09:00:00+00:00
Before importing into your CRM or outreach tool, run this checklist:
- [ ] Remove records without a phone number or website unless you have another enrichment path.
- [ ] Verify that the category matches your ideal customer profile.
- [ ] Exclude businesses below your minimum rating threshold.
- [ ] Deduplicate against your existing CRM by phone or domain.
- [ ] Add a
sourcecolumn that references Google Maps and the collection date. - [ ] Review the list for chain locations if you are targeting independent businesses.
- [ ] Confirm compliance with local telemarketing and privacy regulations before calling.
Build vs Buy: Where CoreClaw Fits
| Approach | Best for | Maintenance burden | Lead quality | Time to first list |
|---|---|---|---|---|
| Manual research | A handful of high-value accounts | Low | High | Hours |
| Open-source scraper + custom code | Engineering teams with scraping experience | High | Medium | Days to weeks |
| Managed scraper API | Teams that need reliable, scalable lists | Low | High | Minutes |
Building your own Google Maps scraper in 2026 means fighting TLS fingerprinting, proxy rotation, CAPTCHA handling, and selector drift every time Google updates its front end. For most sales and marketing teams, that engineering time is better spent on messaging and follow-up.
The CoreClaw Google Maps Scraper returns structured business records in bulk, including reviews, reviewer details, contact information, hours, and photos, without requiring you to manage proxies or browser farms. If your use case is not covered by the ready-made worker, you can build a custom worker in Python, Node.js, or Go and deploy it through the CoreClaw worker console.
For a broader view of ready-made scrapers, the CoreClaw Store lists workers for Google Maps, Google Search, Amazon, Instagram, YouTube, TikTok, and other common targets.
Business Use Cases
Local SEO agencies use lead lists to prospect businesses with weak review profiles. A restaurant with a 3.2 rating and no website is an obvious candidate for reputation management or web design services.
SaaS outbound sales target specific categories in a city or metro area. A fleet-management tool might search for "delivery service," "courier," or "logistics company" within a 50-mile radius.
Franchise and multi-location brands monitor competitor density when choosing new locations. A structured Maps dataset shows which neighborhoods are saturated and which are underserved.
Event and conference organizers build sponsor or attendee prospect lists around venues and nearby businesses. A tech conference in Chicago can target "software company" and "IT consultant" listings within walking distance of the venue.
Market research teams compare category counts, ratings, and review velocity across cities to measure local market health.
Limitations and Compliance
A lead scraper is a research accelerator, not a license to ignore rules. Keep the following limits in mind:
- Public data only. Only collect information that is publicly visible on the business listing. Do not attempt to access private accounts, restricted pages, or non-public contact details.
- Respect platform terms. Google Maps has terms of service and technical protections. Run requests at a reasonable pace and review the latest terms before deploying.
- No credential abuse. Do not use stolen credentials, fake accounts, or session hijacking to access data.
- No CAPTCHA evasion. If the site presents a challenge, stop and reduce frequency or switch to an officially supported data source.
- Privacy and telemarketing laws. Phone numbers collected from public listings may still be regulated by local laws. In many jurisdictions you need a lawful basis to call or message a business. Review GDPR, TCPA, or equivalent rules that apply to your market.
- Data freshness. A scraped record is a snapshot, not a live feed. Re-run your workflow on a schedule and treat old records as suspects.
For more on collecting public web data responsibly, see the public web data compliance guide on the CoreClaw Web Data Guide.
FAQ
Do I need a Google Maps API key?
No. A Google Maps scraper reads public business listings directly. You do not need a Google Cloud project, API key, or OAuth flow.
What output format does the CoreClaw Google Maps Scraper use?
CoreClaw workers typically return JSON, CSV, or Excel. You can choose the format that fits your downstream workflow.
Can I get email addresses from Google Maps?
No. Google Maps listings generally do not expose email addresses. Use the website or phone number to initiate contact, or run a separate enrichment step on the domain using a tool you trust.
How do I avoid duplicate leads?
Deduplicate by phone number first, then by domain, then by place ID or plus code. Chain locations often share a domain but have different addresses, so decide whether you want one entry per brand or one per location.
How often should I refresh the lead list?
For most outreach campaigns, weekly or monthly refreshes are enough. Daily refreshes are useful only when you are monitoring fast-moving markets or competitor openings.
Can I schedule the workflow to run automatically?
Yes. You can run the script from cron, GitHub Actions, or a cloud scheduler. Pair it with a managed scraper that exposes an API endpoint so you do not have to maintain the browser layer.
Is this legal?
Laws vary by jurisdiction. Collecting publicly visible business information is generally permissible in many regions, but you must still comply with platform terms, privacy laws, and telemarketing regulations. This guide does not constitute legal advice; consult a lawyer for your specific use case.
Next Steps
Start by defining your ideal customer profile: category, location, minimum rating, and minimum review count. Then run a small test with the CoreClaw Google Maps Scraper, normalize the output with the Python script above, and review a dozen records manually before scaling.
If Google Maps is only one of several data sources you need, browse the CoreClaw Store for ready-made workers covering search, e-commerce, and social platforms. For a deeper look at Google Maps scraping workflows, the CoreClaw Google Maps scraper guide walks through public-data collection patterns and compliance considerations.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.