Google Maps Business Scraper — Phones & Hours
Pricing
from $0.43 / 1,000 business delivereds
Google Maps Business Scraper — Phones & Hours
Search Google Maps for local businesses by term and location. Export names, phones, websites, addresses, ratings, review counts, and weekly hours. No Google API key. $0.50 per 1,000 delivered businesses.
Pricing
from $0.43 / 1,000 business delivereds
Rating
0.0
(0)
Developer
Meka.im
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Search Google Maps by keyword and location to build a structured list of local businesses. Export names, phones, websites, addresses, ratings, review counts, and opening hours for $0.50 per 1,000 delivered businesses. No Google API key is required.
Tool preview: Explore Google Maps Lead Finder for recorded examples and the current preview status. Browse the tools directory for other sources.
- Contact, address, hours, accessibility, ranking and location in the base price
- Core business fields aligned with the leading Google Maps Actor
- No charge for duplicates, failures, or empty searches
- No Google API key required
Quick start: scrape Google Maps business data
- Put your search terms in the Search terms field, one per line.
- Click Start.
- Export the Dataset, or read it with the API calls below.
{"searchStringsArray": ["dentist in Austin TX", "florist in Boston"],"maxCrawledPlacesPerSearch": 20,"language": "en"}
Google Maps scraper input
| Field | Type | Default | Notes |
|---|---|---|---|
searchStringsArray | array of strings | required | One search term per line. Terms that name a place work best. Searched separately, results keep your order |
locationQuery | string | A single place to search in. Combined with each term | |
city / county / state / postalCode | string | Optional, added to the location | |
countryCode | string | Filters by confirmable country: only businesses whose address country or time zone confirms this country are returned and charged; unconfirmable ones are left out. Detection relies on Google's data and may be imperfect | |
language | string | en | Language of names, categories and hours |
maxCrawledPlacesPerSearch | integer | 20 | 1 to 60. See Limits |
customGeolocation | object | GeoJSON geometry; its centre becomes the map centre | |
categoryFilterWords | array | Keep only these categories | |
searchMatching | string | all | only_includes or only_exact to match on the name |
placeMinimumStars | string | Drop businesses below this rating | |
website | string | allPlaces | withWebsite or withoutWebsite |
Duplicate search terms are searched once. A business that appears under two terms is written once.
All four filters run on each page after it is fetched and do not change the upstream query. Anything they remove is not charged. If a page leaves fewer rows than you asked for, the Actor fetches the next page, up to three pages and 60 businesses per search term.
Inputs from the reference Actor
This Actor also accepts the other inputs of the leading Google Maps Actor so an existing input file runs unchanged, even though they are not shown in the editor:
- Accepted, no effect: review, image, contact, lead, social-profile and competitor-analysis options,
scrapePlaceDetailPage,skipClosedPlacesand the other add-on switches. Setting any of them to a non-default value is reported in the run log and in the run summary, so it is never silent. - Rejected:
startUrls,placeIdsandallPlacesNoSearchAction. These change the input mode entirely, and quietly ignoring them would return results you did not ask for. A run that sets one stops with an explanation instead.
Google Maps business data output
One row per business, in the order of your search terms.
| Field | Type | Notes |
|---|---|---|
fid | string | Google's feature ID. The stable key for joining and de-duplication |
placeId | string | Google Place ID, ChIJ… |
cid | string | Decimal customer ID used by maps?cid= links |
kgmid | string | Knowledge Graph machine ID |
businessProfileId | string | Google Business Profile ID |
url | string | Google Maps link |
title | string | Business name |
categoryName | string | Primary category |
categories | array | All categories, primary first |
description | string or null | Editorial summary |
tagline | string or null | Short tagline. Additional field |
address | string | Street address without the business name |
street / city / state / postalCode / countryCode / neighborhood | string or null | Address split into parts |
location | object | { lat, lng }, each null when Google has no coordinates |
phone | string or null | As Google displays it |
phoneUnformatted | string or null | Digits only |
website | string or null | |
totalScore | number or null | Average rating |
reviewsCount | number or null | See Limits |
openingHours | array | { day, hours }, Monday first |
openingHoursComplete | boolean | Whether all seven days are present |
openState | string or null | Open/closed text at the moment of the scrape. Not a permanent-closure flag |
timezone | string | IANA timezone |
additionalInfo | object | Accessibility attributes |
thumbnail | string or null | Preview image |
searchString / language / rank / scrapedAt | Where this row came from |
Example row, trimmed:
{"fid": "0x8644b4eb0b01986f:0x6b241d4769ed491e","placeId": "ChIJbxgBC-u0RIYRHknsaUcdJGs","title": "ATX Family Dental","categoryName": "Dentist","address": "1700 S 1st St, Austin, TX 78704","city": "Austin", "state": "TX", "postalCode": "78704", "countryCode": "US","location": { "lat": 30.2482229, "lng": -97.7559705 },"phone": "(512) 717-3147", "phoneUnformatted": "+15127173147","website": "https://www.atxfamilydental.com/","totalScore": 4.9, "reviewsCount": 902,"openingHours": [{ "day": "Monday", "hours": "8 AM–5 PM" }],"openingHoursComplete": true,"additionalInfo": { "Accessibility": [{ "Wheelchair accessible entrance": true }] },"searchString": "dentist in Austin TX", "rank": 1}
Google Maps business scraper pricing
$0.50 per 1,000 delivered businesses.
- A search term that returns nothing is not charged. Unlike some alternatives, this Actor does not fill an empty search with unrelated businesses.
- Duplicate search terms and businesses that appear under more than one term are charged once.
- Filtered-out businesses are not written and not charged.
- Failed searches are not charged.
- A resumed run does not refetch or recharge a business already in the Dataset.
The run summary records delivered alongside charged, so you can reconcile the bill against the Dataset.
Google Maps business data coverage and limits
Stated here rather than discovered later.
Up to 60 businesses per search term, in pages of 20. The default is 20, which requests only the first page; existing inputs that leave this field unset keep the single-page behavior and cost. Values from 21 to 40 use up to two pages; values from 41 to 60 use up to three. Higher values are capped at 60 with a warning in the run log and summary.
The Actor follows continuation cursors until the requested number is reached or the search ends. A page that Google returns with fewer than 20 raw results ends that term early, and an empty page ends it too. Results removed by the country filter or by your filters do not make an otherwise full upstream page short: if Google returned 20 raw results, pagination can continue even when fewer than 20 remain after filtering. Businesses are de-duplicated by fid across pages, and rank stays continuous in page order and Google's order within each page.
If a later page fails, that search term publishes no partial batch and is not marked complete. On resume, it starts again from the first page. Businesses already written to the Dataset are not delivered or charged twice, and other completed terms are not refetched.
Review count and weekly hours come and go. Google answers this endpoint with either a full payload or a lite one, and the choice is per response: either all 20 businesses carry the review count and seven-day hours, or none of them do. The run detects a lite payload and retries, waiting between attempts because that is what actually helps. Most businesses end up complete; some do not, and openingHoursComplete tells you which. reviewsCount is null when the payload omitted it.
openState is not a closure flag. It is the open or closed text at the moment of the scrape, so a business that is simply shut for the night reads as closed. This version does not extract a permanent-closure flag.
additionalInfo covers accessibility only. Other attribute groups are not part of the search response.
Not included in this version: review text, rating distribution, image counts and full image sets, claim status, emails and website contacts, and more than 60 businesses per search term.
Compatibility
Designed to match the core search semantics of the leading Google Maps Actor, not its full input contract. Field names, types and null rules for the core business fields follow that Actor, verified field by field against 100 rows of a live run on 2026-09-20: 99.94% semantic match across 24 core fields and 1,632 comparisons.
Result sets are not identical. Google returns a somewhat different set of businesses for the same search from one call to the next. When you ask for more than 20, this version reads up to three separate pages for that term.
API and automation
Read the Dataset directly:
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?format=csv&clean=true" \-H "Authorization: Bearer APIFY_TOKEN"
Start a run and wait for its Dataset in one call:
curl -X POST "https://api.apify.com/v2/acts/ACTOR_ID/run-sync-get-dataset-items" \-H "Authorization: Bearer APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"searchStringsArray":["dentist in Austin TX"]}'
Each run also writes an OUTPUT record to the key-value store with how many search terms were requested and deduplicated, and how many businesses were delivered, charged, de-duplicated, filtered out, skipped on resume, and how many searches returned nothing or failed.
Continuation cursor (product API)
The /prd/v1/google-maps-business-scraper product API returns an opaque cursor. Pass it back with the same input and unit to get the next page. A cursor is bound to the normalized input, search term and per-term limit, and the product enforces a maximum of three pages and 60 businesses per term.
A malformed, damaged, mismatched or out-of-range cursor returns HTTP 400 with code invalid_cursor before any upstream request. The PRD boundary separately rejects a non-string or oversized cursor as bad_request. The cursor carries a format/checksum and input-binding check and validates the allowed page range; it is not a secret signature. A caller that recomputes a well-formed cursor is outside that integrity guarantee, while the hard delivery boundary remains three pages and 60 businesses per term.
Build a local lead generation workflow
Use this Actor to discover businesses, then continue with:
- Website Email Finder to find email addresses published on each business website.
- Google Maps Reviews Scraper to collect sorted customer reviews for the businesses you found.
The shared business website and Google Maps identifiers make the three Actors easy to connect in Apify Tasks, schedules, API calls, n8n, or Make.
FAQ
Why did I get fewer than the number I asked for?
Google returned a short or empty page, the three-page limit was reached, or a filter removed some businesses. Filters continue to the next page when more can be fetched, up to three pages and 60 businesses per term. Filtered-out businesses are not charged.
A business has no phone or website. Was I charged?
Yes. That is a real answer: the business does not publish one. A row is only skipped when it has no stable identifier.
openingHoursComplete is false. Why?
Google answered with its lite payload for that request and the retries did not land a full one. The hours you do get are correct, just not the whole week.
My run stopped early.
If stoppedOnBudget is true in the run summary, the run hit the maximum charge you allowed. Raise the limit and start it again. Businesses already delivered are not refetched or recharged.
Can I search by Place ID or a Google Maps URL?
Not in this version. A run that sets placeIds or startUrls stops with an explanation rather than returning something else.
Can I get reviews?
Not from this Actor. See Limits.
Privacy
This Actor sends one small telemetry event when a run starts and one when it finishes, so we can measure reliability and decide what to build next. An event carries your search terms, the public filters you set, and run counters: how many results you asked for, how many were delivered, how long the run took, and which error categories came up.
An event never carries your Apify token, cookies, authorization headers, API keys, proxy credentials, request headers, or any scraped result. URLs are reduced to a hostname, a path shape, a public resource ID, and a short allowlist of public query parameters — usernames, passwords, fragments and every other query parameter are removed before the URL leaves the run. Your Apify user ID is stored only as a keyed one-way hash, never in the clear.
Search terms are kept for 90 days and then deleted. After that only lowercase aggregate counts remain, and those are what the trend reports are built from.
To switch telemetry off, tick Disable usage telemetry under Advanced options. With that option on, the Actor sends no telemetry events.
Legal
This Actor is independently developed and is not affiliated with, endorsed by, or sponsored by Google.
It reads a public endpoint. It does not sign in, does not use cookies or credentials, and does not reach anything behind a login. You are responsible for how you use the data, including any applicable terms and data-protection rules.