Google Maps Scraper avatar

Google Maps Scraper

Pricing

from $3.00 / 1,000 google maps leads

Go to Apify Store
Google Maps Scraper

Google Maps Scraper

Extract business leads from Google Maps with verified emails, phones & social profiles. 50+ niches (HVAC, dentists, lawyers, real estate & more). DNS/SMTP email verification. $0.003/lead — up to 10x cheaper than alternatives. HubSpot/Salesforce export. MCP-ready for AI agents.

Pricing

from $3.00 / 1,000 google maps leads

Rating

0.0

(0)

Developer

Japi Cricket

Japi Cricket

Maintained by Community

Actor stats

1

Bookmarked

28

Total users

8

Monthly active users

2 days ago

Last modified

Share

Google Maps Lead Scraper

What does Google Maps Lead Scraper do?

Scrape Google Maps businesses with leadQualityScore (0-100 lead-prioritization signal), bestCallTime (when to actually call them), verified emails, phone numbers, social media profiles, star distribution, review topic tags, opening hours, service options, popular times (7-day busy chart), photo counts, unclaimed-listing detection, and review-recency signals — no API key needed. 50+ niches, 4 output formats (Default, HubSpot, Salesforce, Full Contact), pay-per-result at $3/1K. Works with AI agents (Claude, GPT, Cursor) via MCP.

Unlike most Google Maps scrapers that use heavy browser automation (Playwright/Puppeteer at 1-4 GB memory), this scraper uses an HTTP-only approach with Chrome TLS fingerprinting. That means 32× less memory, ~2.7× faster wall time (parallel query execution by default), and the lowest cost on Apify — while delivering 63+ data fields per lead including a composite leadQualityScore that no other Google Maps scraper offers, derived bestCallTime for sales outreach timing, lastReviewDate + daysSinceLastReview for activity signals, popular times, review topic tags, contact-form detection, and categorized attributes — fields most competitors charge separately for or don't offer at all.

Why choose this over 5 separate Google Maps scrapers?

  • enrichmentDepth toggle — single dial (fast / balanced / deep) replaces 5 individual flags. Picks the right cost / data tradeoff in one click. UNIQUE.
  • leadQualityScoreMinimum filter — set a threshold (0-100); leads below it are dropped at push-time, so you only pay PPE for the leads you actually want. UNIQUE.
  • hasContactForm boolean — detects contact forms on the business website during enrichment. HIGH-value qualifier ("can this business receive inbound web inquiries?")
  • leadQualityScore (0-100) — UNIQUE composite metric combining 11 signals (verified email, phone, website, contact form, review count, recency, claim status, rating, social presence, photo count, commerce URLs). Sort your CRM by this single number and call your hottest leads first. No other Google Maps scraper offers this.
  • bestCallTime — derived from popularTimesHistogram × openingHours, gives you a sales-actionable string like "Tuesday 14:00 (15% busy)". Stop calling restaurants during dinner rush.
  • lastReviewDate + daysSinceLastReview — activity-recency signals. Filter for businesses still actively monitored by their owner.
  • Cheapest on Apify — $3/1K leads with email + social + verification all included (compass charges $4/1K + $4/1K for enrichment + $100/1K for social)
  • Free email extraction + verification — 3-layer pipeline with DNS/SMTP verification + automatic UA-rotation retry on transient 403/429/503 blocks
  • Free social media (7 platforms) — LinkedIn, Facebook, Instagram, YouTube, X, Pinterest, TikTok included (compass charges $100/1K extra)
  • Free popular-times chart — full 7-day × ~18-hour busy histogram per place; identify low-traffic time slots for sales outreach (compass requires place-details-scraped event extra)
  • Free unclaimed-listing flagclaimThisBusiness: true = the business hasn't claimed their Google profile = fresh outreach opportunity
  • Free review topic tags (reviewsTags) — top guided-dining topics aggregated across recent reviews (meal type, price range, noise level, reservation policy, parking ease) as [[label, count], ...]. 100% fill on restaurants, 9-21 tags each. Surface sales-actionable signals like "Difficult to find parking" (4 mentions) or "Reservation required" (14 mentions).
  • Reserve / Menu / Order online URLs — direct OpenTable / Resy / Google Food links extracted from each restaurant
  • Photo count + categorized attributesimagesCount (total Google Maps photos) + additionalInfo grouped by 13 categories (Service options, Highlights, Atmosphere, Crowd, Payments, Children, Parking, etc.)
  • 4 CRM output formats — Default, HubSpot, Salesforce, Full Contact — export directly to your CRM
  • 50+ business niches — auto-generated search queries optimized per niche (HVAC, dentist, lawyer, plumber, etc.) with a tightened niche/category matching layer that keeps tutoring free of private-school clutter, appliance-repair free of retail stores, and daycare free of plant nurseries
  • Parallel query execution — up to 5 search queries in parallel (default 3) for faster runs; zero cost to you
  • Resume-friendly — crashed a long run? Pass resumePlaceIds from the partial dataset to skip already-scraped places; no duplicate PPE charge
  • Niche-aware license extraction — realtor DRE# / TREC# / DOS# / state license #, lawyer bar #, medical NPI, contractor CSLB/ROC/CCB — picked based on your selected niche
  • Strict maxResultsTotal cap — request N, get exactly N leads (not 2N). The push-time hard cap closes the parallel-query race where multiple search terms could each push a full batch before the soft cap fired.
  • Strict per-lead bandwidth discipline — website enrichment capped at ≤500 KB per lead with a pre-fetch byte budget check (never overshoots); keeps Evomi costs predictable and honours the documented budget
  • Slow-URL observability — the log surfaces [slow-fetch] lines for any page that takes ≥2.5 s and [slow-enrich] lines for any place that takes ≥6 s to enrich, so you can diagnose and skip problem domains
  • Global-ready — tested across English, Spanish, French, German, Portuguese, and Japanese; works across US / UK / Australia / Malaysia / EU with the right language + countryCode combo
  • Tested — unit-test suite covers address parsing, email normalization, license extraction, and category matching
  • AI-ready — works with Claude, GPT, and Cursor via MCP protocol

Getting Started

  1. Click "Try for free" at the top of this page
  2. Select a Business Type (e.g., Dentist, Plumber, Restaurant) — or enter custom search queries
  3. Add Locations (e.g., "Chicago IL", "Miami FL", "90210")
  4. Click Start — results appear in the Dataset tab within seconds
  5. Download as JSON, CSV, or Excel — or connect via API, n8n, Make, or Zapier

No API key needed. No setup required. Just select a niche, add a location, and scrape.

Easiest Way to Start

Select a Business Type and add a Location — search queries are generated automatically. For example:

Business TypeLocationAuto-Generated Queries
DentistChicago IL"dentist in Chicago IL", "dental clinic in Chicago IL"
Plumber90210"plumber in 90210", "plumbing company in 90210"
HVACHouston TX"HVAC company in Houston TX", "air conditioning repair in Houston TX"

Or use Custom Search Queries for full control — type anything you'd type into Google Maps.

8 Output Formats

FormatDescriptionBest For
DefaultAll 65+ raw fields in JSON (incl. leadQualityScore, gmbActivityScore, bestCallTime)Developers, custom workflows, data analysis
HubSpotMapped to HubSpot Contact propertiesDirect HubSpot CRM import
SalesforceMapped to Salesforce Lead objectDirect Salesforce import
PipedriveMapped to Pipedrive Person/Organization fields incl. Lead Quality Score, Best Call Time, GMB ActivityDirect Pipedrive CRM import (NEW — no other Google Maps scraper offers this)
Zoho CRMMapped to Zoho Lead Underscore_Case API fieldsDirect Zoho Lead import (NEW)
AirtableTitle Case columns optimized for Airtable basesAirtable import (NEW)
CSV-flatFlattens nested objects (socialProfiles.linkedinsocialProfiles_linkedin, reviewsTagsreviewsTags_top5)Excel users, BI tools that don't handle nested JSON (NEW)
Full ContactNested JSON with contact/org/socialFull Contact enrichment, API integrations

Standard vs Enriched Mode

Every run works in Standard mode (Google Maps data only) or Enriched mode (adds website scraping for emails, social media, and licenses). Enrichment is enabled by default.

What You Get in Standard Mode (enrichWebsites: false)

Fast scraping with 50+ fields from Google Maps data:

  • Business name, category, description, price level
  • Full address (street, city, state, ZIP, country, GPS coordinates)
  • Phone (formatted + raw), website
  • Rating, review count, star distribution (1-5 stars)
  • Review topic tags (reviewsTags) — top guided-dining topics aggregated across recent reviews (meal type, price range, noise level, reservation policy, parking ease) as [[label, count], ...]. 100% fill on restaurants.
  • Opening hours (7 days), per-service hours (Delivery / Takeout etc.), service options
  • Categorized attributesadditionalInfo grouped by 13 categories
  • Popular times — full 7-day × ~18-hour busy histogram + live "currently busy" data when place is open
  • Photo count + main image + business profile photo
  • Reserve / Menu / Order online / Services URLs — direct booking and ordering links
  • claimThisBusiness flagtrue = unclaimed Google Business Profile (fresh sales lead)
  • Google Maps URL, Place ID, CID, Plus Code
  • Closure status (temporarily / permanently)

What You Get in Enriched Mode (enrichWebsites: true)

All Standard fields plus data scraped from each business website:

  • Email address — 3-layer extraction: direct scrape, deep crawl, pattern guessing
  • Email verification — DNS MX lookup + SMTP handshake
  • Social media (7 platforms) — LinkedIn, Facebook, Instagram, YouTube, X, Pinterest, TikTok
  • License numbers — contractor, real estate, legal licenses
  • Enrichment status — enriched, partial, skipped, or failed

When to Use Which Mode

Your GoalRecommended ModeEnrichment?
Quick business directory dataStandardNo
Lead list with emails for outreachEnriched + VerifiedYes
CRM import with contact detailsEnriched + HubSpot/Salesforce formatYes
Market research (ratings, reviews, hours)StandardNo
Competitor monitoringStandardNo
Sales prospecting with social profilesEnrichedYes

Default Output Format

Input Parameters

ParameterTypeDefaultDescription
businessTypestringgeneralBusiness niche (50+ options) — auto-generates 2–4 search terms per niche
locationsstring[][]Cities, areas, or ZIP codes to search
searchQueriesstring[][]Custom Google Maps queries (full control)
zipCodesstring[][]US ZIP codes (alternative to locations)
maxResultsPerSearchTerminteger50Max leads per generated search term (1–500). A plumber niche expands into 3 terms; 50 here can yield up to ~150 leads per location after dedup.
maxResultsTotalintegernoneStrict hard cap on total output across all queries. Enforced at push-time (not just pre-enrichment) so parallel queries can't race past the cap — request 5, get exactly 5. Leave empty for no cap.
languagestringenLanguage for results (29 options). Verified end-to-end on en, es, fr, de, pt, ja — native-language categories like Restaurant français, Friseursalon, ビュッフェ レストラン come back correctly.
countryCodestringusCountry focus (ISO 3166-1 alpha-2). Verified end-to-end across US / UK / AU / MY with local place results. For non-US markets, set language to the local language and (optionally) use a region-matched Evomi residential URL for IP-geolocation parity.
enrichmentDepthstringnoneRecommended over individual flags. Single dial: fast (no enrichment), balanced (default — website enrichment + verification + reviews distribution), deep (balanced + returnAllEmails + includeImages with maxImages bumped to 10). When set, OVERRIDES the 5 individual flags below.
leadQualityScoreMinimuminteger (0-100)nonePush-time filter. Drops leads below this leadQualityScore BEFORE PPE billing. Set to 70 = only pay for hot leads. Leave empty = push everything.
scrapeAfterDatestring (ISO 8601)nonePush-time filter. Drops leads whose most-recent review is older than this date. Set 2026-01-01 to skip abandoned listings. Useful for filtering out long-dead businesses BEFORE PPE billing.
enrichWebsitesbooleantrueExtract emails, social media, licenses, and description from business websites. Ignored when enrichmentDepth is set.
verifyEmailsbooleantrueVerify emails via DNS MX + SMTP
returnAllEmailsbooleanfalseReturn all discovered emails with {source, score} tuples in an emails[] array (top-scored also populates email)
skipCategoryMismatchesbooleanfalseDrop leads whose Google category doesn't match the requested niche. The categoryMismatch flag is always present; this input controls whether mismatches are dropped before output. The niche→category keyword banks were tightened so strict-intent niches (tutoring, appliance repair, pet grooming, daycare, driving school) rarely surface false positives even when this flag is off.
queryConcurrencyinteger3Number of Google Maps search queries to run in parallel (1–5). Default 3 roughly halves wall time for multi-query niches. Set to 1 for sequential, human-like cadence.
resumePlaceIdsstring[][]Resume support. Pass placeIds from a previous partial run to skip them entirely — no re-scrape, no re-enrichment, no PPE charge. Useful for stitching together crashed long runs.
includeOpeningHoursbooleantrueInclude 7-day business hours
includeReviewsDistributionbooleantrueInclude 1-5 star breakdown
includeImagesbooleanfalseInclude photo URLs
outputFormatstringdefaultOutput format: default, hubspot, salesforce, fullcontact

Deprecated: maxResultsPerQuery is still accepted (with a log warning) for backward compatibility with existing runs and schedules — it is an alias for maxResultsPerSearchTerm. New integrations should use the new name plus maxResultsTotal for predictable volume.

Input Example

{
"businessType": "dentist",
"locations": ["Chicago IL", "Houston TX"],
"maxResultsPerSearchTerm": 25,
"maxResultsTotal": 100,
"enrichWebsites": true,
"verifyEmails": true,
"outputFormat": "default"
}

Output Fields (66+ fields)

#FieldTypeDescriptionExample
1titlestringBusiness name"Downtown Dental - Loop"
2categoryNamestringPrimary category"Dentist"
3categoriesarrayAll categories["Dentist", "Cosmetic dentist", "Oral surgeon"]
3acategoryMismatchbooleantrue when the Google category does NOT match the selected niche. Always present. Use skipCategoryMismatches: true to drop these.false
4descriptionstringGoogle Maps description, with a fallback to the business website's <meta name="description"> / <meta property="og:description"> / first paragraph when Google Maps has none"Family dental practice since 1985"
5priceLevelstringPrice range"$$", "$50-100", "$100+"
6addressstringFull address"25 E Washington St STE 1921, Chicago, IL 60602"
7streetstringStreet address"25 E Washington St STE 1921"
8citystringCity"Chicago"
9statestringState code"IL"
10postalCodestringZIP/postal code — canonical 5-digit format for US; CRM-friendly (no ZIP+4 suffix)"60602"
11countryCodestringCountry code"US"
12neighborhoodstringNeighborhood"The Loop"
13plusCodestringGoogle Plus Code"V9MF+68 Chicago, Illinois"
14locationobjectGPS coordinates{"lat": 41.883, "lng": -87.627}
15phonestringFormatted phone"(773) 692-5401"
16phoneUnformattedstringRaw phone"+17736925401"
17websitestringBusiness website"https://www.downtown-dental.com/"
18totalScorenumberRating (1-5)4.7
19reviewsCountintegerTotal reviews1362
20reviewsDistributionobjectStar breakdown{"oneStar":12,"twoStar":8,...,"fiveStar":1192}
20areviewsTagsarrayTop guided-dining topics aggregated across recent reviews — [[label, count], ...] sorted by frequency. Restaurants get 9-21 distinct tags covering meal type, price range, noise level, reservation policy, parking, recommendation strength.[["Dinner", 28], ["$100+", 22], ["Reservations recommended", 6], ["Difficult to find parking", 4]]
20blastReviewDatestring (ISO)Most-recent review's posting date"2026-03-09T01:56:21.774Z"
20cdaysSinceLastReviewintegerDays between today and lastReviewDate — recency signal for "actively-monitored business"48
21openingHoursarray7-day hours[{"day":"Monday","hours":"8 AM-5 PM"},...]
21aadditionalOpeningHoursobjectPer-service hours (e.g. Delivery, Takeout, Drive-through) when different from main hours{"Delivery": [{"day":"Monday","hours":"12-9 PM"},...]}
22serviceOptionsarrayAvailable services (flat list)["Onsite services", "Online appointments"]
22aadditionalInfoobjectCategorized attributes grouped into 13 buckets: Accessibility, Service options, Highlights, Popular for, Offerings, Dining options, Amenities, Atmosphere, Crowd, Planning, Payments, Children, Parking{"Atmosphere": [{"Cozy": true}, {"Romantic": true}], "Payments": [{"Credit cards": true}]}
22bpopularTimesHistogramobject7-day × ~18-hour busy chart. Keys: Mo/Tu/We/Th/Fr/Sa/Su. Each is an array of {hour, occupancyPercent} (0-100). Identifies low-traffic windows for sales outreach.{"Mo": [{"hour": 19, "occupancyPercent": 70}, ...], ...}
22cpopularTimesLivePercentnumberReal-time "currently X% busy" — only populated when scraping during the place's open hours64
22dpopularTimesLiveTextstringReal-time text — "Less busy than usual" / "A little busier than usual" / "As busy as it gets" — only when open"Less busy than usual"
22d1peakBusyHourobjectGlobally busiest hour across the week, derived from popularTimesHistogram{"day":"Sa","dayFullName":"Saturday","hour":18,"occupancyPercent":100}
22d2quietestHourobjectLeast-busy non-zero hour across the week{"day":"Tu","dayFullName":"Tuesday","hour":8,"occupancyPercent":6}
22d3bestCallTimestringSales-actionable: when to call this business. Quietest weekday slot in 10 AM-4 PM window."Tuesday 10:00 (16% busy)"
22d4isAdvertisementbooleantrue when result was a sponsored placement (currently always false for organic results — reserved for future ad-detection logic)false
22eclaimThisBusinessbooleantrue = unclaimed Google Business Profile (fresh sales lead opportunity)false
22freserveTableUrlstringDirect OpenTable / Resy / Google Reserve link (restaurants)"https://www.google.com/maps/reserve/v/dine/c/..."
22ggoogleFoodUrlstringDirect food order link (Grubhub / DoorDash via Google)"https://www.google.com/searchviewer/..."
22hmenustringExternal menu URL when Google links to onenull on most listings
22iservicesLinkstringExternal services menu URL (service businesses)null on most listings
23temporarilyClosedbooleanTemp closed flagfalse
24permanentlyClosedbooleanPerm closed flagfalse
25imageUrlstringMain listing photo"https://lh3.googleusercontent.com/..."
25aimagesCountintegerTotal Google Maps photo count for the listing12787
26profilePhotoUrlstringBusiness profile photo"https://lh6.googleusercontent.com/..."
27placeIdstringGoogle Place ID"ChIJTZHMAqUsDogRT23QNnloow4"
28cidstringGoogle Company ID"18391531526889988045"
29urlstringGoogle Maps link"https://www.google.com/maps/place/?q=place_id:..."
30emailstringEmail address — normalized: lowercase domain, no mailto: prefix, no query strings"info@downtown-dental.com"
30aemailsarrayOptional (returnAllEmails: true). All discovered emails as [{email, source, score}], sorted best-first. source is scraped / deep-crawl / guessed.[{"email":"...", "source":"scraped", "score":13}]
31emailVerifiedbooleanEmail verifiedtrue
32emailVerificationStatusstringVerification detail"mx_valid_smtp_failed" or "verified"
33emailSourcestringHow email was found"scraped", "deep-crawl", or "guessed"
34socialProfiles.linkedinstringLinkedIn URL"https://linkedin.com/company/..."
35socialProfiles.facebookstringFacebook URL"https://facebook.com/downtowndentalloop"
36socialProfiles.instagramstringInstagram URL"https://instagram.com/downtowndentalloop"
37socialProfiles.youtubestringYouTube URL"https://youtube.com/@..."
38socialProfiles.twitterstringX/Twitter URL"https://x.com/..."
39socialProfiles.pintereststringPinterest URL"https://pinterest.com/..."
40socialProfiles.tiktokstringTikTok URL"https://tiktok.com/@..."
41licenseNumberstringNiche-aware professional license: realtor (DRE#, BRE#, TREC#, DOS#, FL SL/BK), legal (state bar numbers), medical (NPI), contractor (CSLB, ROC, CCB, CGC, …)"DRE# 01234567" or "NPI 1234567890" or "FL Bar #12345"
42enrichmentStatusstringEnrichment result"enriched", "partial", "skipped"
43businessTypestringNiche label"Dentist"
44searchStringstringQuery that found it"dentist in Chicago IL"
45rankintegerPosition in results1
46scrapedAtstringISO timestamp"2026-04-05T13:25:22.578Z"
47leadQualityScoreinteger (0-100)UNIQUE composite signal — combines 11 weighted signals (verified email, phone, website, contact form, review count + recency, claim status, rating, social presence, photo count, commerce URLs). Sort your CRM by this to call your hottest leads first. No other Google Maps scraper offers this.95 (highest in real test data)
48hasContactFormbooleantrue when the business website has a detectable contact/inquiry form. Adds 5 pts to leadQualityScore. Only populated when enrichWebsites: true (or enrichmentDepth: balanced/deep).true
49addressVerifiedbooleantrue when all address components (street + city + state + postalCode + countryCode) are present + valid (5-digit ZIP for US). Filter for true to avoid mailing campaigns to incomplete addresses.true
50gmbActivityScorestringCategorical activity signal: "Active" (review in last 90d + claimed + rating ≥3.0), "Stale" (review in last 365d but missing one signal), "Abandoned" (no reviews 365d+ OR unclaimed with <10 reviews), "Unknown". Identifies neglected listings = pure sales opportunity."Active"

Output Example

{
"title": "Downtown Dental - Loop",
"categoryName": "Dentist",
"categories": ["Dentist", "Cosmetic dentist", "Dental clinic", "Emergency dental service"],
"description": null,
"priceLevel": null,
"address": "25 E Washington St STE 1921, Chicago, IL 60602",
"street": "25 E Washington St STE 1921",
"city": "Chicago",
"state": "IL",
"postalCode": "60602",
"countryCode": "US",
"neighborhood": "The Loop",
"plusCode": "V9MF+68 Chicago, Illinois",
"location": { "lat": 41.883029, "lng": -87.626714 },
"phone": "(773) 692-5401",
"phoneUnformatted": "+17736925401",
"website": "https://www.downtown-dental.com/locations/loop/",
"totalScore": 4.7,
"reviewsCount": 1362,
"reviewsDistribution": { "oneStar": 12, "twoStar": 8, "threeStar": 30, "fourStar": 120, "fiveStar": 1192 },
"openingHours": [
{ "day": "Sunday", "hours": "Closed" },
{ "day": "Monday", "hours": "8 AM - 5 PM" },
{ "day": "Tuesday", "hours": "8 AM - 5 PM" },
{ "day": "Wednesday", "hours": "8 AM - 5 PM" },
{ "day": "Thursday", "hours": "8 AM - 5 PM" },
{ "day": "Friday", "hours": "8 AM - 2 PM" },
{ "day": "Saturday", "hours": "Closed" }
],
"serviceOptions": ["Onsite services", "Online appointments", "Wheelchair accessible"],
"temporarilyClosed": false,
"permanentlyClosed": false,
"imageUrl": "https://lh3.googleusercontent.com/...",
"placeId": "ChIJTZHMAqUsDogRT23QNnloow4",
"cid": "18391531526889988045",
"url": "https://www.google.com/maps/place/?q=place_id:ChIJTZHMAqUsDogRT23QNnloow4",
"email": "info@downtown-dental.com",
"emailVerified": true,
"emailVerificationStatus": "mx_valid_smtp_failed",
"emailSource": "scraped",
"socialProfiles": {
"facebook": "https://facebook.com/downtowndentalloop",
"instagram": "https://instagram.com/downtowndentalloop",
"linkedin": null,
"youtube": null,
"twitter": null,
"pinterest": null,
"tiktok": null
},
"enrichmentStatus": "enriched",
"businessType": "Dentist",
"searchString": "dentist in Chicago IL",
"rank": 3,
"scrapedAt": "2026-04-05T13:25:22.578Z"
}

Use Cases

  • Lead generation — build prospect lists with verified emails and social profiles for outreach
  • Market research — analyze ratings, reviews, pricing, service options across hundreds of businesses
  • Local SEO audits — track Google Maps rankings, review counts, and business info accuracy
  • Sales prospecting — CRM-ready output with phone, email, and 7 social platforms
  • Competitor monitoring — schedule weekly runs to track changes over time

How to Run

  1. Set businessType to your target niche (e.g., "dentist") or use searchQueries for custom searches
  2. Add locations — cities, ZIP codes, or areas (e.g., ["Chicago IL", "Houston TX"])
  3. Set enrichWebsites: true for emails and social media
  4. Set verifyEmails: true for DNS/SMTP email verification
  5. Set outputFormat: "default" (or omit — it's the default)
  6. Click Start — results in the Dataset tab

HubSpot CRM Format

Export leads directly into HubSpot with pre-mapped Contact properties.

Input Example

{
"businessType": "lawyer",
"locations": ["Miami FL"],
"maxResultsPerSearchTerm": 25,
"maxResultsTotal": 50,
"enrichWebsites": true,
"verifyEmails": true,
"outputFormat": "hubspot"
}

Output Fields

HubSpot FieldSourceExample
First NameAuto-detected (person names only)"" (empty for businesses)
Last NameBusiness name or person last name"ANDREW C. DEMOS, P.A."
EmailEmail address"andrew@demoslaw.com"
Phone NumberPhone (raw)"+1 954-589-0119"
Company NameBusiness name"ANDREW C. DEMOS, P.A."
Website URLBusiness website"http://www.demoslaw.com/"
Street AddressFull address"1806 N Flamingo Rd Suite 322, Pembroke Pines, FL 33028"
CityCity"Pembroke Pines"
State/RegionState"FL"
Zip CodePostal code"33028"
Lifecycle StageAlways "lead""lead"
Lead StatusAlways "New""New"
LinkedInLinkedIn URL"https://linkedin.com/in/..."
FacebookFacebook URL"https://facebook.com/..."
InstagramInstagram URL"https://instagram.com/..."
Twitter/XX URL"https://x.com/..."
Google Maps RatingRating (1-5)4.9
Google Reviews CountTotal reviews58
License NumberProfessional license""
Email VerifiedVerification resulttrue
Lead SourceAlways "Google Maps Scraper""Google Maps Scraper"
NotesEnrichment notes"Email verified (MX valid, domain accepts email)"
Date AddedTimestamp"2026-04-05T13:25:22.578Z"

Output Example

{
"First Name": "",
"Last Name": "ANDREW C. DEMOS, P.A.",
"Email": "andrew@demoslaw.com",
"Phone Number": "+1 954-589-0119",
"Company Name": "ANDREW C. DEMOS, P.A.",
"Website URL": "http://www.demoslaw.com/",
"Street Address": "1806 N Flamingo Rd Suite 322, Pembroke Pines, FL 33028",
"City": "Pembroke Pines",
"State/Region": "FL",
"Zip Code": "33028",
"Lifecycle Stage": "lead",
"Lead Status": "New",
"Email Verified": true,
"Lead Source": "Google Maps Scraper",
"Notes": "Email is pattern-guessed; Email verified (MX valid, domain accepts email)",
"Date Added": "2026-04-05T13:25:22.578Z"
}

Use Cases

  • CRM import — download CSV and import directly into HubSpot Contacts
  • Sales automation — connect via Zapier/Make to auto-create HubSpot contacts from each run
  • Lead scoring — use Google Maps Rating and Reviews Count for lead prioritization

How to Run

  1. Set outputFormat: "hubspot"
  2. Enable enrichWebsites and verifyEmails for maximum data
  3. Download CSV and import via HubSpot's Import tool, or connect via Zapier/Make

Salesforce CRM Format

Export leads as Salesforce Lead objects ready for import.

Input Example

{
"businessType": "real_estate_agent",
"locations": ["Phoenix AZ"],
"maxResultsPerSearchTerm": 25,
"maxResultsTotal": 50,
"enrichWebsites": true,
"verifyEmails": true,
"outputFormat": "salesforce"
}

Output Fields

Salesforce FieldSourceExample
FirstNameAuto-detected""
LastNameBusiness name"Century 21 Northwest Realty"
EmailEmail"info@c21northwest.com"
PhoneFormatted phone"(602) 555-1234"
CompanyBusiness name"Century 21 Northwest Realty"
WebsiteBusiness website"https://c21northwest.com"
StreetStreet address"4350 E Camelback Rd"
CityCity"Phoenix"
StateState"AZ"
PostalCodeZIP"85018"
CountryCountry code"US"
LeadSource"Google Maps""Google Maps"
Status"Open - Not Contacted""Open - Not Contacted"
RatingHot/Warm/Cold based on score"Hot" (4.5+), "Warm" (3.5+), "Cold"
DescriptionSummary with license, rating, reviews"Rating: 4.8 (523 reviews)"

Use Cases

  • Salesforce import — download CSV and use Data Import Wizard or Data Loader
  • B2B prospecting — auto-create Salesforce Leads via API integration
  • Territory mapping — build lead lists by city/ZIP code for sales territories

How to Run

  1. Set outputFormat: "salesforce"
  2. Enable enrichWebsites for email and social data
  3. Download CSV and import via Salesforce Data Import Wizard

Full Contact Format

Export as nested JSON matching Full Contact's enrichment schema.

Input Example

{
"businessType": "contractor",
"locations": ["Atlanta GA"],
"maxResultsPerSearchTerm": 25,
"maxResultsTotal": 50,
"enrichWebsites": true,
"verifyEmails": false,
"outputFormat": "fullcontact"
}

Output Fields

SectionFieldsDescription
namegiven, family, fullPerson/business name breakdown
emailsvalue, type, verifiedEmail addresses with verification status
phonesvalue, typePhone numbers
organizationsname, website, titleBusiness information
locationsstreet, city, region, postalCode, countryFull address breakdown
socialProfilestype, urlSocial media profiles (7 platforms)
metadatasource, rating, reviews, license, enrichmentStatusScrape metadata

Use Cases

  • API integration — feed directly into Full Contact or similar enrichment APIs
  • Data pipeline — nested JSON structure for custom ETL workflows
  • Contact deduplication — structured format for matching across data sources

How to Run

  1. Set outputFormat: "fullcontact"
  2. Results are nested JSON — best consumed via API or JSON processing tools

50+ Business Niches

Select a niche and provide locations — search queries are generated automatically with niche-optimized terms:

CategoryNiches
Home ServicesHVAC, Plumber, Roofer, Electrician, Contractor, Landscaper, Pest Control, Cleaning, Solar, Painter, Pool Service, Garage Door, Fencing, Moving, Appliance Repair
HealthcareDentist, Chiropractor, Medical Clinic, Med Spa, Veterinarian, Physical Therapy, Orthodontist, Oral Surgeon, Optometrist, Pharmacy
LegalLawyer, Personal Injury, Criminal Defense, Family Law, Immigration, Bankruptcy
ProfessionalReal Estate Agent, Property Management, Mortgage Broker, Insurance, Accountant, Financial Advisor
Food & HospitalityRestaurant, Bar, Cafe, Catering
AutomotiveAuto Repair, Car Dealer, Detailing, Towing
Beauty & WellnessHair Salon, Nail Salon, Day Spa, Gym, Pet Grooming
EducationDaycare, Tutoring, Driving School
EventsWedding Venue, Photographer, Planner, Florist
OtherHome Inspector, Tattoo, Storage, Laundromat, Printing

Or use General Business with your own custom search queries for any niche not listed.

Pricing — Pay Per Result, No Monthly Fee

$3.00 per 1,000 leads — email extraction, social media, email verification, star distribution, service options, and CRM formatting all included at no extra cost.

FormatPrice / resultPrice / 1,000FieldsBest For
Default$0.003$3.0066+ fieldsDevelopers, data analysis, custom workflows
HubSpot$0.003$3.0023 fieldsDirect HubSpot CRM import
Salesforce$0.003$3.0015 fieldsDirect Salesforce Lead import
Full Contact$0.003$3.00Nested JSONAPI integrations, enrichment pipelines

Cost examples:

  • 100 business leads with emails: $0.30
  • 500 dentists in Chicago with social profiles: $1.50
  • 1,000 plumbers nationwide with HubSpot export: $3.00
  • 10,000 restaurants with ratings and hours: $30.00

You only pay for results delivered. Platform compute costs are included.

Why This Google Maps Scraper?

  • Cheapest on Apify — $3/1K with everything included (competitors charge $4-$10/1K after add-ons)
  • Free email extraction + verification — 3-layer pipeline with DNS/SMTP included (others charge $2.50-$4/1K extra)
  • Free social media (7 platforms) — LinkedIn, Facebook, Instagram, YouTube, X, Pinterest, TikTok (compass charges $100/1K extra)
  • 4 CRM output formats — HubSpot, Salesforce, Full Contact — no other Google Maps scraper offers this
  • 50+ business niches — auto-generated, niche-optimized search queries
  • Star distribution included — exact 1-5 star breakdown, not just the average rating
  • Service options included — Dine-in, Takeout, Delivery, etc. (most scrapers skip this)
  • HTTP-only architecture — Impit with Chrome TLS fingerprint impersonation (no bloated browser)
  • 128 MB memory — runs on minimal resources (peak observed ≈50 MB), keeping compute costs low
  • Strict bandwidth cap — website enrichment is capped at ≤500 KB per lead via a pre-fetch byte budget (Layer-1 pages fetched sequentially with a budget check before each request, so the cap is never overshot). Observed ~415 KB/lead on enriched runs.
  • Parallel query execution — up to 5 queries concurrent (default 3); roughly 2.7× wall-time reduction on multi-query niches
  • Enrichment retry with UA rotation — transient 403/429/503 blocks get one automatic retry with a fresh User-Agent
  • 429 diagnostic warning — if Google Maps rate-limits repeatedly, the log surfaces an actionable recommendation to configure an Evomi residential proxy
  • Slow-URL diagnostics — the run log surfaces [slow-fetch] for any single URL taking ≥2.5 s and [slow-enrich] for any place taking ≥6 s to enrich, so you can identify and exclude problem domains
  • Strict category precision — niche→category keyword banks reviewed and tightened (e.g. tutoring no longer surfaces private K-12 schools, appliance_repair no longer accepts retail "Appliance store" results, pet_grooming excludes pet supply stores, daycare excludes plant nurseries, driving_school excludes golf driving ranges)
  • Strict maxResultsTotal — request N, get exactly N. Hard cap is checked at the push-to-dataset boundary so parallel queries can't race past the limit.
  • No proxy required — direct exit works reliably for Google Maps; optional Evomi residential override available for high-volume runs or non-US geolocation
  • Resume support — pass resumePlaceIds from a partial dataset to pick up where a crashed run left off
  • Human-like behavior — randomized delays with Box-Muller distribution jitter
  • 100% field-level accuracy — verified against live Google Maps ground-truth; null fields are returned only when the source is also empty
  • 20 unit tests — covering address parser, email normalization, license extractor, and category matcher (run npm test)
  • MCP-compatible — works with AI agents (Claude, GPT, Cursor) out of the box

How We Compare

FeatureThis Scrapercompass/crawlerlukaskrivkamicroworlds
Price / 1K leads$3.00$4.00$5.00$3.50
Email extractionIncluded free+$4.00/1K+$2.50/1K+$3.50/1K
Social mediaIncluded free (7 platforms)+$100/1K+$100/1KUnavailable
Email verificationIncluded freeNot availableNot availableNot available
leadQualityScore (0-100 composite)Included free — UNIQUENot availableNot availableNot available
leadQualityScoreMinimum push-time filterIncluded — UNIQUE (saves PPE on cold leads)Not availableNot availableNot available
scrapeAfterDate push-time filterIncluded — UNIQUE (skips abandoned listings)Not availableNot availableNot available
enrichmentDepth single-toggle (fast/balanced/deep)Included — UNIQUE (cleaner UX)Not availableNot availableNot available
hasContactForm qualifierIncluded freeNot availableNot availableNot available
addressVerified booleanIncluded freeNot availableNot availableNot available
gmbActivityScore (Active/Stale/Abandoned)Included freeNot availableNot availableNot available
CRM formats8: default + HubSpot + Salesforce + FullContact + Pipedrive + Zoho + Airtable + CSV-flatNoneNoneNone
bestCallTime (sales-action timing)Included free — UNIQUENot availableNot availableNot available
peakBusyHour / quietestHourIncluded freeRequires post-processingNot availableNot available
lastReviewDate + daysSinceLastReviewIncluded freeNot availableNot availableNot available
Star distributionIncludedIncludedUnknownUnknown
Review topic tags (reviewsTags)Included free (9-21 tags/restaurant)Requires extra event, often nullOften null in basicUnavailable
Popular times (7-day busy chart)Included freeRequires place-details-scraped extra eventNot in basicUnavailable
Live "currently busy" %Included freeRequires extra eventNot in basicUnavailable
Photo count (imagesCount)Included freeIncludedIncludedUnavailable
Reserve / Menu / Order URLsIncluded freeRequires extra eventNot in basicUnavailable
Categorized attributes (additionalInfo, 13 buckets)Included freeIncludedIncludedUnavailable
Per-service hours (additionalOpeningHours)Included freeIncludedIncludedUnavailable
Unclaimed-listing flag (claimThisBusiness)Included freeIncludedIncludedUnavailable
CRM output formats4 formatsNoneNoneNone
50+ niche presetsYesNoNoNo
Memory128 MB4,096 MB1,024 MBVaries
Enrichment bandwidth / lead≤500 KB (strict cap, pre-fetch budget)UncappedUncappedUncapped
Parallel queriesYes (default 3)NoNoNo
Strict maxResultsTotal (exact hard cap)Yes (push-time gate)NoNoNo
Niche→category precision (flag + filter)Yes (tightened keyword banks)NoNoNo
Slow-URL observability ([slow-fetch] / [slow-enrich])YesNoNoNo
Resume from partial datasetYes (resumePlaceIds)NoNoNo
Niche-aware license extractionYes (realtor/legal/medical/contractor)Realtor-onlyNoNo
Languages proven end-to-end6 (en, es, fr, de, pt, ja) — 29 availableVariesVariesVaries
Data fields per lead50+50+30+20-30

Key advantages:

  1. One actor with everything included — competitors charge separately for email ($4/1K), social ($100/1K), and enrichment ($4/1K). We include it all for $3/1K.
  2. Lowest effective price — $3/1K vs $8-$108/1K for the same data elsewhere
  3. Free email verification — DNS MX + SMTP check on every email, zero extra cost
  4. CRM-ready output — HubSpot, Salesforce, Full Contact formats that no competitor offers
  5. Lightweight + fast — 128 MB HTTP-only (32× less memory than compass's 4,096 MB browser-based approach) and parallel query execution for roughly 2.7× wall-time reduction on multi-query niches
  6. Production-resilient — UA-rotated enrichment retry, 429 diagnostic warnings, crash-resume support, and a unit test suite

MCP Integration for AI Agents

This scraper works with AI agents via the Model Context Protocol (MCP). Connect it to Claude Desktop, Cursor, GPT, or any MCP-compatible client.

Setup:

  1. Go to mcp.apify.com
  2. Add "Google Maps Lead Scraper" to your MCP server
  3. Ask your AI: "Find 50 dentists in Chicago with emails"

Example prompts for your AI agent:

  • "Scrape 20 plumbers in Houston TX and export to HubSpot format"
  • "Find restaurants in Manhattan with ratings above 4.5"
  • "Get all HVAC companies in Dallas with verified emails"
  • "Search for lawyers in Miami and export to Salesforce"

Works with Claude Desktop, Cursor, GPT via MCP, and any other MCP-compatible AI client.

Integrations

n8n

  1. Add the Apify node in your n8n workflow
  2. Select "Google Maps Lead Scraper" as the actor
  3. Configure the business type, location, and output format
  4. Connect the output to your CRM, Google Sheets, or database

Make.com (Integromat)

  1. Add the Apify module to your scenario
  2. Select "Run Actor" and choose this scraper
  3. Map the JSON output fields to your downstream modules
  4. Use for automated lead enrichment, market monitoring, or CRM syncing

Zapier

  1. Create a new Zap with Apify as the trigger or action
  2. Select "Run Actor" and configure with this scraper's actor ID
  3. Map output fields to Google Sheets, HubSpot, Salesforce, or Slack
  4. Trigger on schedule or from a webhook

REST API & SDKs

Use the Apify API, JavaScript SDK, or Python SDK for programmatic access:

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("get-leads/google-maps-scraper---best-value-for-money").call(
run_input={
"businessType": "dentist",
"locations": ["Chicago IL", "Houston TX", "Miami FL"],
"maxResultsPerSearchTerm": 25,
"maxResultsTotal": 100, # optional hard cap across all queries
"queryConcurrency": 3, # parallel queries (1-5) — ~2.7x wall-time reduction
"enrichWebsites": True,
"verifyEmails": True,
"returnAllEmails": False, # set True for emails[] array with {source, score}
"skipCategoryMismatches": False, # set True to drop off-niche results
"outputFormat": "default",
}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(f"{item['title']}{item['email']}{item['phone']}")

Resuming a crashed run

If a long run failed partway through, pull the placeIds from the partial dataset and pass them back via resumePlaceIds — the second run skips them entirely (no re-scrape, no re-enrichment, no duplicate PPE):

partial = list(client.dataset(failed_run["defaultDatasetId"]).iterate_items())
already_seen = [it["placeId"] for it in partial if it.get("placeId")]
resume_run = client.actor("get-leads/google-maps-scraper---best-value-for-money").call(
run_input={
"businessType": "dentist",
"locations": ["Chicago IL", "Houston TX", "Miami FL"],
"maxResultsPerSearchTerm": 25,
"maxResultsTotal": 100,
"resumePlaceIds": already_seen, # <-- skip these
"enrichWebsites": True,
"outputFormat": "default",
}
)

Tips for Best Results

  1. Be specific with location — "Chicago IL" works better than just "Chicago"
  2. Use niche selection — auto-generated queries are optimized per business type
  3. Start small — test with 20 results via maxResultsTotal: 20, then scale up
  4. Enable enrichment for lead gen — email hit rate 80%+, social media hit rate 70%+
  5. Use maxResultsTotal for predictable volume — caps the whole run after dedup so 2-city × 3-search-term expansions don't surprise you
  6. Turn up queryConcurrency for big runs — the default 3 halves wall time; 4–5 can cut it further at the cost of slightly higher 429 risk
  7. Save placeIds for resume — if a run fails partway, the resumePlaceIds input lets you skip already-scraped places on the retry
  8. Disable star distribution for speed — set includeReviewsDistribution: false to reduce cost by ~30%
  9. Enable returnAllEmails for sales teams — get every discovered email with source + confidence score, not just the top winner
  10. Enable skipCategoryMismatches for clean B2B lists — drops off-niche results before PPE billing
  11. Non-English markets — pair language with a matching countryCode (e.g. language=fr, countryCode=fr for France, language=ja, countryCode=jp for Japan); for IP-geolocation parity use a region-matched Evomi residential URL
  12. Check [slow-fetch] log lines — if a specific domain keeps appearing, exclude it from enrichmentPages or ship it to a follow-up run with tighter concurrency
  13. Schedule regular runs — via Apify Schedules for weekly/monthly lead lists
  14. Export to your CRM — use HubSpot or Salesforce format for zero-config import

FAQ

How many leads can I scrape? Up to 500 per search term. Each business niche auto-expands into 2–4 search terms, so a single niche + city can yield up to ~2,000 leads per run. Use maxResultsTotal to set an overall ceiling.

Which countries are supported? All countries where Google Maps operates. Set the language and countryCode parameters to match your target market. End-to-end testing has been performed on US, UK, Australia, and Malaysia — all return accurate local businesses with correct native-language categories. For other markets, the same parameters work (29 languages available including en, es, fr, de, it, pt, nl, ja, ko, zh-CN, ar, ru, etc.), though we haven't explicitly verified every combination.

How do I get MY/UK/AU/EU-local results? Set countryCode to the ISO code (my, gb, au, de, …) and language to the matching language code. For IP-geolocation parity — important when Google biases results by requester IP — point RESIDENTIAL_PROXY_URL at a region-matched Evomi sticky-hardsession URL (Evomi supports per-country sticky sessions). Without a region-matched IP the results are still good thanks to countryCode, but a local IP sharpens rank-1 relevance.

How accurate are the emails? ~80% hit rate on enriched runs. Emails are found via 3-layer extraction (direct scrape, deep crawl, pattern guessing), normalized (domain lower-cased, mailto: / query-strings stripped), and verified with DNS MX + SMTP handshake. Enable returnAllEmails: true to receive every discovered email with its source (scraped / deep-crawl / guessed) and relevance score — useful when multiple contacts per business matter (e.g. firstname.lastname@ alongside info@).

How accurate is the rest of the data? Core fields (title, phone, website, address, totalScore, reviewsCount, categoryName) are verified against live Google Maps ground truth sampled across all 10 business-category families — all match on direct-compare fields. Null fields are returned only when the source is also empty (e.g. a business that hasn't published opening hours on Google Maps will come back with openingHours: null), which is the correct behaviour — a null for genuinely-absent data is a correct null, not a gap.

What does categoryMismatch mean? Google Maps sometimes mixes related-but-off-niche results into a search (e.g. "tutoring" returns private schools, "veterinarian" returns pet shops). Every lead carries a categoryMismatch: true/false flag based on whether its Google categoryName matches the niche you selected. Enable skipCategoryMismatches: true to drop mismatches entirely; otherwise leave the flag in the output and filter client-side.

What license formats are detected? licenseNumber is niche-aware:

  • Realtors & property — California DRE#/BRE#, Texas TREC#, New York DOS#, Florida SL/BK, generic "Real Estate License #"
  • Lawyers — state bar numbers (SBN, Florida Bar #, generic "Bar No.", "Attorney License")
  • Medical (dentists, doctors, vets, etc.) — NPI (10-digit National Provider Identifier) and "MD/DDS/DO/DVM License"
  • Contractors (HVAC, plumber, roofer, electrician, solar, painter, etc.) — California CSLB#, Arizona ROC#, Oregon CCB#, Florida CGC/CCC/CBC, generic "Contractor License #"

What's the star distribution? The exact count of 1-star, 2-star, 3-star, 4-star, and 5-star reviews — not just the average rating.

What are service options? Structured business attributes like "Dine-in", "Takeout", "Delivery", "Wheelchair accessible", "Online appointments" — extracted from the Google Maps detail page. The flat serviceOptions array gives you a quick scannable list; the richer additionalInfo object groups the same data into 13 categories (Service options, Highlights, Atmosphere, Crowd, Payments, Children, Parking, etc.) for filterable CRM ingestion.

What is gmbActivityScore? Categorical signal classifying each listing's Google Business Profile activity:

  • Active — review in last 90 days AND owner has claimed listing AND rating ≥ 3.0. Reachable, healthy lead.
  • Stale — review in last 365 days but missing at least one signal above. Worth reaching out, may need re-engagement pitch.
  • Abandoned — no reviews in 365+ days OR unclaimed listing with very few reviews. Either skip or use as "we'll handle your Google presence" pitch.
  • Unknown — not enough data to classify (e.g., never been reviewed).

Complements leadQualityScoreActive listings should also have high lead quality scores.

What is addressVerified? Boolean — true when all 5 address components (street, city, state, postal code, country code) are present and the postal code is valid (5 digits for US). Filter for addressVerified: true to avoid sending mail campaigns to incomplete addresses, or to validate data quality before CRM ingestion.

What is scrapeAfterDate and how is it different from leadQualityScoreMinimum? Both are push-time filters that drop leads BEFORE PPE billing. Different criteria:

  • scrapeAfterDate filters by lastReviewDate — drops listings with stale activity. Use to skip abandoned businesses.
  • leadQualityScoreMinimum filters by composite quality score — drops listings without enough lead-gen signals (no email, no phone, no website, etc.). Use to skip low-information leads.

You can combine both: scrapeAfterDate: "2026-01-01" + leadQualityScoreMinimum: 70 = "only pay for active leads with verified contact data."

What output format should I use? (Pipedrive, Zoho, Airtable, CSV-flat — what's the difference?)

  • default — all 65+ raw fields with nested objects. Best for developers and custom workflows.
  • hubspot / salesforce / pipedrive / zoho — pre-mapped to each CRM's standard import field names. Download CSV and direct-import into your CRM with zero column mapping.
  • airtable — Title Case columns (Lead Quality Score, Has Contact Form) optimized for Airtable bases.
  • csvflat — flattens nested objects (socialProfiles.linkedinsocialProfiles_linkedin, reviewsTagsreviewsTags_top5 joined string). Best for Excel users and BI tools that don't handle nested JSON.
  • fullcontact — nested JSON for Full Contact-style enrichment pipelines.

What is enrichmentDepth and when should I use it? A single dial that picks the right cost / data tradeoff in one click. Replaces the matrix of enrichWebsites + verifyEmails + returnAllEmails + includeImages + includeReviewsDistribution:

  • fast — scraping only, no website visits, no email verification, no images, no reviews distribution. Cheapest + fastest. Great for bulk-prospecting where you only need place names + phones.
  • balanced (default behavior) — website enrichment + email verification + reviews distribution. ~80% email hit rate, ~97% margin. The canonical mode.
  • deep — everything above + returnAllEmails (multi-email array with confidence scores) + includeImages (up to 10 photo URLs per place). Maximum data per lead.

When set, enrichmentDepth overrides the 5 individual flags. Leave empty to use the individual flags as before (full backward compatibility).

What is leadQualityScoreMinimum? A push-time filter: leads with leadQualityScore below this threshold are DROPPED before being charged for. Set to 70 = "only pay for high-quality reachable leads (verified email, recent reviews, claimed listing, decent rating)". Set to 50 = "drop only the skeleton listings with no contact data". Leave empty (default) = push every result. This directly saves PPE budget on cold leads.

What is hasContactForm? Boolean detected during website enrichment. true when the business website has a contact/inquiry form (form element with name/email/message inputs). Useful qualifier — businesses with contact forms accept inbound web inquiries, making them more reachable. Adds 5 points to leadQualityScore. Only populated when website enrichment is enabled.

What is leadQualityScore? A composite 0-100 metric that blends 10 lead-gen signals into a single sortable number. Components (additive):

  • Verified email: +20
  • Phone present: +10
  • Website present: +10
  • 25+ reviews (established business): +10
  • Last review within 90 days (active): +15
  • Claimed Google Business Profile: +10
  • Rating ≥ 4.0: +10
  • Any social profile: +5
  • 10+ photos on listing: +5
  • Has reservation/order URL: +5

Sort your dataset by leadQualityScore desc to prioritize the hottest leads. A score of 75-100 = high-quality reachable lead; 50-74 = decent lead, missing 1-2 signals; <50 = enrich further before outreach. No other Google Maps scraper offers this composite metric.

What is bestCallTime? A pre-computed sales-action recommendation derived from the place's popularTimesHistogram × openingHours. We pick the quietest hour during typical business outreach window (10 AM – 4 PM, weekdays preferred) so your sales call doesn't land during dinner rush. Format: "Tuesday 14:00 (15% busy)". Falls back to globally quietest non-zero hour when business-window doesn't match.

What are peakBusyHour and quietestHour? Derived globally from popularTimesHistogram. peakBusyHour = hour-of-week with highest occupancy (typically dinner/lunch rush). quietestHour = lowest non-zero occupancy hour (avoids closed slots). Both are objects: {day: "Sa", dayFullName: "Saturday", hour: 18, occupancyPercent: 100}.

What is lastReviewDate and daysSinceLastReview? Most-recent review's posting timestamp (ISO 8601) and integer days since. Filter for daysSinceLastReview < 30 to find businesses with active customer engagement (= owner is monitoring = reachable).

What is reviewsTags? Top "guided dining" topics aggregated across recent reviews from the Google Maps reviews-listing endpoint. For restaurants, every review prompts the reviewer for structured signals (meal type, price range, noise level, reservation policy, parking ease, recommendation strength) — we collect those answers and tally them. Result: [["Dinner", 28], ["$100+", 22], ["Reservations recommended", 6], ...] sorted by frequency. Typical fill: 9-21 tags per restaurant. Aspect ratings (Food/Service/Atmosphere) are also surfaced as ["Food (avg 4.7★)", N] entries with the aggregate star rating + sample size. Most useful for sales pitches like "They consistently mention 'Difficult to find parking' — let's pitch them on a delivery integration".

What is popularTimesHistogram? A 7-day × ~18-hour busy chart showing how busy the place typically is each hour of each day. Format: {Mo: [{hour: 19, occupancyPercent: 70}, ...], Tu: [...], ..., Su: [...]}. Useful for sales outreach timing (call when not busy), demand-pattern analysis, and competitive benchmarking. Bonus fields popularTimesLivePercent and popularTimesLiveText populate when scraping during the place's open hours, surfacing "currently 64% busy" / "Less busy than usual" real-time data.

What does claimThisBusiness mean? true = the business owner has NOT claimed their Google Business Profile yet. This is a high-value sales signal — unclaimed listings are common for newer or smaller businesses, and claim-the-listing services are an easy first conversation. false = the listing has been claimed by the business owner.

What URLs does the scraper extract from info[75] (the Google action panel)? Up to four direct booking/ordering links per place: reserveTableUrl (OpenTable / Resy / Google Reserve), menu (external menu URL when Google links to one), googleFoodUrl (Grubhub / DoorDash via Google), and servicesLink (services menu URL for service businesses). All four are null when not applicable to the listing.

Do I need proxies? No. The scraper runs without a proxy by default — Google Maps' public endpoint accepts direct traffic at typical scrape volumes.

For high-volume or globally-distributed runs you can optionally enable an Evomi residential proxy:

  • Set the actor env var RESIDENTIAL_PROXY_URL to an Evomi URL in @-format, e.g. http://USER:PASS@rp.evomi.com:1000.
  • Evomi is billed at $0.49/GB — the enrichment pipeline caps bandwidth at ≤500 KB/lead (≈0.5 GB per 1,000 leads) so the proxy adds ~$0.25 per 1K leads, preserving the actor's ≥50% profit margin.
  • Bandwidth is logged per run as Enrichment bandwidth: X MB total (Y KB/lead) so you can verify the budget.

Apify Residential Proxy is NOT supported. Its $12.50/GB price would make the $3/1K PPE actor unprofitable (15× the margin budget). If RESIDENTIAL_PROXY_URL contains proxy.apify.com, the actor aborts with a clear error at startup. Use Evomi (or no proxy) instead.

How is this so cheap? HTTP-only architecture uses 32× less memory than browser-based scrapers (128 MB vs 4,096 MB), strictly caps website enrichment bandwidth at ≤500 KB per lead (sequential Layer-1 fetch with a pre-fetch byte budget; observed ≈415 KB/lead on enriched runs), and runs up to 3 queries in parallel by default for ~2.7× wall-time reduction on multi-query runs. Lower compute + strictly-bounded bandwidth + less wall time = lower price for you.

How do I resume a crashed run? Fetch the placeId values from the partial dataset of the failed run, then re-run with resumePlaceIds: [...] containing those IDs. Every place in the list is skipped on the new run — no re-scrape, no re-enrichment, and most importantly no duplicate PPE charge. The second run picks up from where the first left off.

Can I run this on a schedule? Yes! Use Apify Schedules to run daily, weekly, or monthly scrapes automatically.

What format can I export data in? CSV, Excel, JSON, Google Sheets, or via API. Plus 4 built-in CRM formats: Default, HubSpot, Salesforce, Full Contact.

Support

Questions, feedback, or custom scraping needs? Contact us at get.leads.apify@gmail.com.

Follow us on LinkedIn for updates, tips, and new scraper releases.