Google Maps Scraper - Places, Phone, Website & Reviews
Pricing
Pay per event
Google Maps Scraper - Places, Phone, Website & Reviews
Google Maps places scraper: search term + location in, places out with name, star rating, review count, category, address, opening hours, and optionally phone and website. Uses a real browser because Maps renders results client-side. No API key. Export CSV, JSON or Excel.
Pricing
Pay per event
Rating
5.0
(1)
Developer
Flash Scrape
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Search Google Maps like a person would and export the businesses: name, category, rating, review count, address, hours - with phone and website available per place. Runs a real hardened browser so you don't have to.
- The feed, scrolled - ~20-30 places per search, the same set a user sees
- Phone & website - the two fields worth money, fetched per place when enabled
- Measured fill - phone 81%, website 77% on the reference run
- Consent-wall proof - exits are pinned outside the EU so runs don't die on Google's cookie page
Quick start
Open the actor, keep the defaults, press Save & start. The reference run below is exactly that. Then adjust the input for your own search and export CSV, JSON or Excel from the dataset tab - or call it from the API and read the dataset programmatically.
A real row
Straight from a reference run, trimmed to the highlights:
{"name": "Thomas Dental","category": "Dentist","address": "2546 E Thomas Rd","rating": 4.8,"reviews_count": 785,"hours_summary": "Open \u00b7 Closes 6\u202fPM","is_open_now": true,"maps_url": "https://www.google.com/maps/place/Thomas+Dental/data=!4m7!3m6!1s0x872b6ca2bc0f1247:0x2eb64f5293c1af02!8m2!3d33.4805563!4d-112.0260627!16s%2Fg%2F1vgx16lr!19sChIJRxIPvKJsK4cRAq_Bk1JPti4?authuser=0&hl=en&rclk=1","place_id": "0x872b6ca2bc0f1247:0x2eb64f5293c1af02","has_orders_online": false,"raw_card_text": "Thomas Dental | Thomas Dental | 4.8 | Dentist \u00b7 \ue934 \u00b7 2546 E Thomas Rd | Open \u00b7 Closes 6\u202fPM","search_term": "dentist"}
How it works
A hardened real browser (camoufox) opens Maps with a US-pinned exit, runs your search, scrolls the results feed until it stops growing (~20-30 places), parses every card, and - when details are enabled - opens each place for phone and website.
Every column, with measured fill
| Column | Filled on the reference run |
|---|---|
name | 100% |
category | 100% |
address | 100% |
rating | 100% |
reviews_count | 100% |
hours_summary | 100% |
is_open_now | 100% |
maps_url | 100% |
place_id | 100% |
has_orders_online | 100% |
raw_card_text | 100% |
search_term | 100% |
search_location | 100% |
scraped_at | 100% |
phone | 81% |
website | 78% |
plus_code | 81% |
price_level | 0% |
A missing value is null; the column set never shifts, so your CSV import is stable across runs.
Input reference
| Field | Type | Default | Notes |
|---|---|---|---|
searchTerms | array | ['dentist'] | What to look for, e.g. ['dentist', 'plumber']. Each term is searched separately. |
location | string | Austin, TX | City, region or area to search in, e.g. 'Austin, TX'. Combined with each search term as ' |
maxPlaces | integer | 60 | Hard cap per run. Google's feed yields roughly 20-60 places per search term before it stops loading more. |
scrollDepth | integer | 6 | How many times to scroll the results list. Volume on Google Maps comes from scrolling, not pagination: a fresh |
fetchContactDetails | boolean | False | Phone number and website are NOT in the results list; getting them needs one extra page load per place, so thi |
minRating | string | 0 | e.g. 4.0. Blank or 0 = no filter. Places with no rating at all are treated as 0. |
minReviews | integer | 0 | Filters out places with too few reviews to judge. 0 = no filter. |
onlyWithWebsite | boolean | False | Requires 'Also fetch phone and website' to be on, since the website is only visible on the place panel. |
proxyConfiguration | object | {'useApifyProxy': True | Recommended. Your exit IP decides what Google shows: a European IP gets the EU cookie-consent page instead of |
Pricing
Pay per result - charged only for rows delivered; the current rate is on this page's Pricing tab. Zero results cost zero, and failed fetches are never billed.
Use cases
- Local lead lists - A category+city into contactable rows
- Competitor mapping - Every rival within a search, with ratings and review counts
- Data verification - Cross-check your CRM's local accounts against live Maps data
Honest limits
We would rather say it here than have you find out on a paid run:
- A search yields what Maps shows (~20-30 places) - volume comes from running more searches, not deeper scrolls
- Google intermittently serves bot checks; the run reports it honestly and retries with a fresh exit rather than billing air
Scheduling & integrations
Every input works identically from the API, so this actor drops into schedules and pipelines: run it on an Apify Schedule for a recurring export, point a webhook at the finished run to push rows into Slack, Google Sheets (via Zapier/Make/n8n) or your warehouse, and page through the dataset with the standard Dataset API. Saved tasks keep your configuration one click away.
FAQ
Is this against Google's ToS? It reads public pages the way a browser does. For an alternative with zero Google exposure, see local-business-leads on this account (OpenStreetMap-based).
Why a browser? Maps renders everything client-side - there is no lighter honest way.
Related actors from this account
Built by Flash Scrape - measured claims, stable columns, no API keys. Something missing? Open an issue on this actor and ask.