Google Maps Business Scraper | $1 per 1,000
Pricing
$1.00 / 1,000 unique business results
Google Maps Business Scraper | $1 per 1,000
Scrape unique Google Maps business listings by city, region, or country. Export names, addresses, phones, websites, ratings, review counts, opening hours, photos, and coordinates. Fast, API-ready, and priced at $1 per 1,000 successful results.
Pricing
$1.00 / 1,000 unique business results
Rating
0.0
(0)
Developer
DataScraperES
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
3 days ago
Last modified
Categories
Share
Scrape unique Google Maps business listings from cities, regions, or whole countries. Export business names, addresses, phone numbers, websites, ratings, review counts, opening hours, photos, categories, and coordinates in a clean dataset ready for lead generation, local SEO, market research, or automation.
Price: $0.001 per unique business successfully written to the dataset — $1.00 per 1,000 results. There is no Actor-start fee.
No Google Places API key, OAuth setup, or external account is required.
What this Actor does
Provide one or more geographic locations and one or more Google Maps search queries. The Actor searches every requested query in every location, expands coverage across the target area, filters geographic spillover, and writes unique businesses to the default Apify dataset.
For example, these inputs:
- locations:
Madrid,Barcelona - queries:
dentists,orthodontists
produce searches for both queries in both cities. If the same business appears in multiple searches, it is written and billed only once because results are deduplicated globally by Google Place ID.
Key benefits
- Global geographic targeting: search cities, municipalities, regions, states, or countries.
- Coverage beyond a single Google Maps search: the target area is divided automatically into geographic sectors.
- Strict area filtering: businesses outside the resolved target boundary are excluded.
- Unique results: duplicate Place IDs found across sectors, queries, and locations are not written twice.
- Simple pricing: one chargeable event at $0.001 per unique dataset item.
- Cost controls: use
maxResultsand Apify's Maximum cost per run. - Structured output: 24 documented fields per business.
- Easy automation: run from Apify Console, API, CLI, schedules, webhooks, Make, Zapier, or your own application.
Best use cases
- Build local business prospect lists for sales and outreach.
- Discover companies by category in a city, region, or country.
- Compare market density, ratings, and review counts.
- Find business websites and public phone numbers.
- Enrich a CRM with Google Maps identifiers and location data.
- Create or maintain local business directories.
- Research competitors and branch coverage.
- Map retail, hospitality, healthcare, or service-business locations.
- Prepare location datasets for GIS and business intelligence tools.
This Actor returns Google Maps business data. It does not crawl business websites for email addresses or social profiles, and it does not extract individual Google reviews.
Quick start
- Open the Actor's Input tab.
- Enter a location such as
Madrid. - Enter a search query such as
dentists. - Keep
countryCodealigned with the location, for exampleES. - Set Max Results to
20for a small test. - Click Start.
- Open the Output or Dataset tab to inspect and download the results.
Minimal input:
{"locations": ["Madrid"],"queries": ["dentists"],"language": "es","countryCode": "ES","maxResults": 20}
At the configured price, a completed 20-result run costs $0.02 in Actor event charges.
Input reference
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
locations | Array of strings | Yes | — | Cities, regions, states, or countries to search. Use a country name for the widest coverage and highest potential number of results. |
queries | Array of strings | Yes | — | Google Maps search terms. Every query runs in every location until the global result limit is reached. |
language | String | Yes | es | Language used for Google Maps results. Choose one of 100 available languages. |
countryCode | String | Yes | ES | Country used to disambiguate and constrain locations. Choose one of 100 available countries and markets. |
maxResults | Integer | No | 1000 | Global maximum number of unique businesses written across the complete run. 0 means unlimited. |
Locations
Use clear geographic names that match countryCode:
{"locations": ["Madrid", "Barcelona", "Valencia"],"countryCode": "ES"}
Locations can have different geographic sizes:
- city:
Chicago - county:
Cook County - state or region:
California - country:
Singapore
For the widest coverage and highest potential number of results, enter the
country name itself in locations and select its matching countryCode:
{"locations": ["Spain"],"countryCode": "ES","maxResults": 10000}
This searches across the country instead of limiting discovery to one city or
region. Selecting ES without using Spain as the location does not turn a
city search into a country search. Country-wide runs usually take longer and
can cost more, while maxResults remains the global output and billing limit.
For ambiguous names, include the state or region in the location text, for
example Springfield, Illinois.
Queries
Queries work like searches a person would type into Google Maps:
{"queries": ["Italian restaurants","dental clinics","coworking spaces"]}
Specific queries usually produce more relevant datasets than broad terms. Related queries can improve discovery, but a business matched by several queries is still stored only once.
Language
The input form provides a validated dropdown with 100 unique language options. The most commonly used options appear first, followed by the extended list:
af, am, ar, az, be, bg, bn, bs, ca, cs, cy, da,
de, el, en, es, et, eu, fa, fi, fil, fr, ga, gl,
gu, ha, he, hi, hr, hu, hy, id, ig, is, it, ja,
jv, ka, kk, km, kn, ko, ku, ky, lb, lo, lt, lv,
mg, mi, mk, ml, mn, mr, ms, mt, my, nb, ne, nl,
nn, no, ny, or, pa, pl, ps, pt, ro, ru, rw, sd,
si, sk, sl, sm, sn, so, sq, sr, st, su, sv, sw,
ta, te, tg, th, tk, tl, tr, tt, uk, ur, uz, vi,
xh, yo, zh, and zu.
Language affects the text returned by Google Maps, including categories, descriptions, and opening-day labels where available.
Country code
The input form provides a validated dropdown with 100 unique countries and markets. Each option shows its name and two-letter ISO 3166-1 code, preventing mistyped or unsupported values. Common examples include:
ES— SpainUS— United StatesGB— United KingdomBR— BrazilDE— GermanyJP— JapanAU— Australia
Available codes:
AE, AM, AO, AR, AT, AU, AZ, BD, BE, BH, BO, BR,
BW, CA, CH, CI, CL, CM, CN, CO, CR, CU, CZ, DE,
DK, DO, DZ, EC, EG, ES, ET, FI, FR, GB, GE, GH,
GR, GT, HN, HR, HU, ID, IE, IL, IN, IQ, IT, JM,
JO, JP, KE, KR, KW, KZ, LB, LK, MA, MX, MY, MZ,
NA, NG, NI, NL, NO, NP, NZ, OM, PA, PE, PH, PK,
PL, PT, PY, QA, RO, RS, RU, RW, SA, SE, SG, SN,
SV, TH, TN, TR, TT, TZ, UA, UG, US, UY, UZ, VE,
VN, ZA, ZM, and ZW.
The country code applies to every location in the run. Use separate runs when searching locations in different countries.
Maximum results
maxResults is a global limit, not a per-query or per-location limit.
Processing stops after that many unique businesses have been successfully
written to the dataset.
If you provide three locations and four queries with maxResults: 1000, the
combined output from all 12 location-query combinations is capped at 1,000
unique businesses.
Use 0 only when you intentionally want the complete planned scan. For large
areas, also set an appropriate run timeout and Maximum cost per run in
Apify's run options.
Input recipes
One category in one city
{"locations": ["London"],"queries": ["accounting firms"],"language": "en","countryCode": "GB","maxResults": 500}
Several related categories
{"locations": ["Miami, Florida"],"queries": ["dentists","orthodontists","dental implants"],"language": "en","countryCode": "US","maxResults": 2000}
Region-wide market research
{"locations": ["Andalusia"],"queries": ["hotels","hostels","holiday apartments"],"language": "es","countryCode": "ES","maxResults": 10000}
Country-scale scan
{"locations": ["Singapore"],"queries": ["restaurants"],"language": "en","countryCode": "SG","maxResults": 0}
Country and large-region scans can require a longer timeout. Start with a capped test before running without a result limit.
Output
Every accepted business is stored as one item in the default dataset. You can inspect results as a table in Apify Console or export them as JSON, JSONL, CSV, Excel, XML, or RSS.
Example result
{"name": "Example Dental Clinic","placeId": "ChIJEXAMPLE","googleMapsUrl": "https://www.google.com/maps/place/?q=place_id:ChIJEXAMPLE","address": "Calle de Ejemplo, 10","city": "Madrid","region": "Madrid","postalCode": "28001","countryCode": "ES","phone": "910 000 000","website": "https://example.com/","avgRating": 4.7,"totalReviews": null,"priceRange": null,"tags": ["Dentista", "Clínica dental"],"description": "","businessPhoto": "https://lh5.googleusercontent.com/.../s800/photo.jpg","photoUrls": ["https://lh5.googleusercontent.com/.../s800/photo.jpg"],"hours": [{"day": "lunes","hours": "9:00–20:00","open24Hour": 9,"close24Hour": 20}],"lat": 40.4168,"long": -3.7038,"discoveryQuery": "dentists","searchLocation": "Madrid","searchCoordinates": "40.4200,-3.7000","scrapeTimestamp": "2026-07-23T11:58:22.031656+02:00"}
Complete output field reference
| Field | Type | Observed presence | Description |
|---|---|---|---|
name | String | 100% | Business name displayed on Google Maps. Required for every accepted result. |
placeId | String | 100% | Stable Google Maps Place ID used to deduplicate results within the run. Required. |
googleMapsUrl | String | 100% | Direct Google Maps link generated from placeId. |
address | String or null | 100% | Street address or the most complete formatted address available. |
city | String or null | 100% | City, municipality, or locality extracted from the listing. |
region | String or null | 100% | Region, state, province, or first-level administrative area. |
postalCode | String or null | 99.70% | Postal or ZIP code. |
countryCode | String or null | 100% | Two-letter ISO country code associated with the result. |
phone | String or null | 97.75% | Public phone number shown on Google Maps. Formatting is returned as displayed and may not include an international prefix. |
website | String or empty | 84.57% | Public website linked from the listing. Tracking redirects are removed when possible. |
avgRating | Number or null | 97.83% | Average Google Maps rating, normally from 1.0 to 5.0. |
totalReviews | Integer or null | 2.72% | Review-count value when present in the returned listing payload. Individual review text and reviewer data are not collected. |
priceRange | String or null | 0% | Price-level text when exposed. It was not present in the measured sample. |
tags | Array of strings | 100% | Business categories associated with the listing, in the selected language. |
description | String or empty | 0% | Business description when exposed. It was empty in the measured sample. |
businessPhoto | String or null | 91.19% | Main business photo URL, normalized to an 800-pixel Google image URL when available. |
photoUrls | Array of strings | 91.19% | Unique photo URLs found for the business. An empty array means no photo URL was exposed. |
hours | Array of objects | 94.37% | Displayed opening-hours entries returned for the listing. An empty array means hours were not exposed. |
lat | Number | 100% | Latitude. A candidate without valid coordinates is not accepted. |
long | Number | 100% | Longitude. A candidate without valid coordinates is not accepted. |
discoveryQuery | String | 100% | First input query that added this unique business to the dataset. |
searchLocation | String | 100% | Input location being processed when the business was first accepted. |
searchCoordinates | String | 100% | Latitude and longitude of the search sector that discovered the business, formatted as lat,lng. |
scrapeTimestamp | ISO 8601 string | 100% | Collection timestamp including its UTC offset. |
How to interpret field availability
Only name and placeId are contractual required fields. Other values depend
on the listing, business category, country, selected language, and the data
returned by Google Maps at collection time.
The percentages above are measured values, not guaranteed fill rates. They
come from 10,000 row observations collected on July 23, 2026 across ten
repeated 1,000-result runs for dentistas in Madrid:
- 100% observed: identity, link, address components, categories, coordinates, discovery context, and timestamp
- 97-99.99% observed: postal code, phone, and average rating
- 80-96.99% observed: website, photos, and opening hours
- below 5% observed: total review count, price range, and description
This sample is useful for planning an integration, but it is not representative
of every category or country. For example, restaurants may expose price
information more often, while listings without an official website will
naturally leave website empty.
Missing-value conventions
The Actor does not invent, predict, or enrich missing Google Maps values:
- missing text can be
nullor an empty string"" - missing arrays such as
photoUrlsandhoursare normally[] - missing numeric values such as
avgRatingortotalReviewsarenull 0is a valid number and should not automatically be treated as missing
When importing CSV or Excel exports, configure your destination to accept empty
cells for optional fields. When consuming JSON, check both null and empty
strings or arrays.
Opening-hours object
Each item inside hours can contain:
| Nested field | Type | Description |
|---|---|---|
day | String or null | Localized day label returned using the selected input language. |
hours | String or null | Human-readable interval such as 10:00–20:00. Use this value when minutes or split periods matter. |
open24Hour | Integer or null | Opening-hour component in 24-hour format. |
close24Hour | Integer or null | Closing-hour component in 24-hour format. |
Google Maps may return only the hours entries available in the current search payload rather than a complete seven-day schedule. Do not assume seven items will always be present.
Identity, discovery, and geographic fields
placeId identifies a Google Maps listing. It is the recommended key for
merging exports or comparing repeated runs. Different branches of the same
brand normally have different Place IDs and remain separate businesses.
lat and long describe the business itself. searchCoordinates describes
the search sector that discovered it; it is not a replacement for the
business coordinates. discoveryQuery and searchLocation explain why the
result is present in a multi-query or multi-location run.
Pricing and billing
The Actor uses pay-per-event pricing with one billable event:
| Event | Price | When it is charged |
|---|---|---|
business-result | $0.001 | Once for each unique business successfully written to the default dataset |
There is no Actor-start charge and no second dataset-item charge.
You are not charged a business-result event for:
- duplicate Place IDs found again in another sector or query
- businesses filtered out because they are outside the target area
- failed search requests
- empty search responses
- candidates that are not written to the dataset
Example costs:
| Unique results | Actor event charge |
|---|---|
| 20 | $0.02 |
| 100 | $0.10 |
| 1,000 | $1.00 |
| 5,000 | $5.00 |
| 10,000 | $10.00 |
| 50,000 | $50.00 |
Control your maximum cost
Use both available safeguards:
- Set
maxResultsto the largest dataset you want. - Set Maximum cost per run in Apify's run options.
The Actor checks the remaining pay-per-event capacity before starting additional work and stops gracefully when the configured charge limit is reached.
Coverage and deduplication
Geographic coverage
The Actor resolves each requested location, plans an area-appropriate search grid, and filters returned coordinates against the target boundary. This reduces the common Google Maps behavior of returning nearby businesses outside the requested city or region.
Where an exact geographic boundary is available, point-in-polygon filtering is used. Otherwise, the resolved bounding area is used. Results with missing or invalid coordinates are excluded because their location cannot be verified.
Unique business rules
Uniqueness is based on placeId across the entire run:
- the same business found in several grid sectors is stored once
- the same business found by several queries is stored once
- the same business found through overlapping locations is stored once
- separate branches with different Place IDs remain separate results
When a result matches more than one query, discoveryQuery records the query
that first added it to the dataset.
Coverage expectations
Google Maps results are dynamic and can vary with query wording, language, location, availability, and upstream changes. No scraper can guarantee a permanent or exhaustive copy of every business. For broader discovery:
- use the country name as the location when you want the widest geographic coverage and the highest potential result count
- combine several specific, related queries
- scan the correct geographic level
- use a sufficient timeout
- compare repeated runs when monitoring changes over time
Performance and run timeout
The default Actor memory is 512 MB and the default timeout is 300 seconds. Small capped runs usually finish well within that window. Larger grids may need more time.
| Workload | Suggested timeout |
|---|---|
| Small test, up to 100 results | 5 minutes |
| City scan, up to 1,000 results | 5-10 minutes |
| Large city or region, up to 10,000 results | 15-30 minutes |
| Unlimited region or country scan | 30-60 minutes or more |
Actual duration depends on the target area's size, number of queries, number of locations, result cap, and Google Maps response conditions.
If a run reaches its timeout, increase the timeout in Run options and start a new run. Do not use unlimited mode for a large area until a capped test has confirmed the expected coverage and cost.
Run through the API
Actor identifier:
datascraperes/actor-google-maps
Synchronous HTTP request
This endpoint waits for the run and returns the default dataset items:
curl -X POST \"https://api.apify.com/v2/acts/datascraperes~actor-google-maps/run-sync-get-dataset-items?timeout=300" \-H "Authorization: Bearer YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"locations": ["Madrid"],"queries": ["dentists"],"language": "es","countryCode": "ES","maxResults": 20}'
For large runs, start the Actor asynchronously and poll the run status instead of waiting on a synchronous HTTP connection.
Python
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("datascraperes/actor-google-maps").call(run_input={"locations": ["Madrid"],"queries": ["dentists"],"language": "es","countryCode": "ES","maxResults": 20,})items = client.dataset(run["defaultDatasetId"]).list_items().itemsprint(f"Downloaded {len(items)} unique businesses")
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('datascraperes/actor-google-maps').call({locations: ['Madrid'],queries: ['dentists'],language: 'es',countryCode: 'ES',maxResults: 20,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(`Downloaded ${items.length} unique businesses`);
Apify CLI
Save the input as input.json, then run:
apify actors call datascraperes/actor-google-maps \--input-file input.json \--output-dataset
Automation and integrations
Because results are stored in the default Apify dataset, you can:
- schedule recurring runs in Apify Console
- trigger workflows through webhooks
- download JSON, CSV, or Excel files
- connect the Actor to Make or Zapier
- import results into Google Sheets, Airtable, a CRM, or a database
- use the Actor from an AI agent through Apify integrations
- combine it with another Actor that enriches the returned websites
When scheduling repeated runs, each run creates its own dataset by default.
Use placeId as the stable key when comparing or merging results across runs.
Troubleshooting
The location cannot be resolved
- Check the spelling.
- Ensure
countryCodematches the location. - Add a state or region to ambiguous names.
- Split locations from different countries into separate runs.
If none of the requested locations can be planned, the Actor fails explicitly instead of reporting a misleading successful empty run.
The run succeeded but returned no businesses
- Try a broader or more common query.
- Verify the selected language and country code.
- Test the same search manually in Google Maps.
- Use a city-level location before attempting a very small district.
An empty but successfully processed search is not billed as a business result.
Fewer businesses were returned than expected
- Check whether
maxResultsor Maximum cost per run was reached. - Increase the run timeout for large areas.
- Add related queries because Google Maps ranks different businesses for different search terms.
- Remember that only businesses with a valid Place ID, name, and coordinates inside the target area are accepted.
A business has no phone number or website
Google Maps does not expose every field for every listing. Missing optional
values can be returned as null, an empty string, or an empty array; the Actor
does not invent or infer them. See How to interpret field availability for
measured fill rates and handling guidance.
The same brand appears several times
Different physical branches normally have different Google Place IDs and are therefore valid separate results. Exact Place ID duplicates are removed.
The run stopped at a specific number of results
The run reached maxResults or the Apify maximum-charge limit. This is a
successful controlled stop, not a scraper error.
A large scan timed out
Increase the timeout in Apify run options, reduce the number of location-query combinations, or split the workload into several runs.
FAQ
Do I need a Google Maps or Google Places API key?
No. The Actor does not require a Google API key or Google Cloud project.
Does it work worldwide?
Yes. Use a valid two-letter country code and a location name that can be resolved in that country. To maximize potential coverage, use the country name itself as the location. Large or complex areas can require longer runs and may cost more than a city search.
Are results unique?
Yes, within each run. Results are deduplicated by Google Place ID across all queries, sectors, and locations.
Are duplicate discoveries charged?
No. The business-result event is charged only when a unique item is
successfully written to the default dataset.
Does it extract email addresses or social profiles?
No. It returns the public website and phone number shown by Google Maps. You can pass the website field to a separate enrichment workflow if needed.
Does it extract individual reviews?
No. It returns avgRating and totalReviews, not individual review text or
reviewer profiles.
Can I search several countries in one run?
The public input uses one shared countryCode, so locations from different
countries should be placed in separate runs.
Can I use it as an API?
Yes. You can start runs and retrieve datasets using the Apify REST API, Python client, JavaScript client, or CLI.
Can I schedule recurring Google Maps exports?
Yes. Use Apify schedules and optionally attach a webhook or integration to process the dataset after each successful run.
Is a result guaranteed to have every field?
No. name and placeId are required. All other fields depend on the
information available for that business on Google Maps.
Responsible use
Use this Actor only for lawful purposes and in accordance with applicable terms, privacy rules, database rights, and data-protection laws. Business data can include personal data in some jurisdictions. You are responsible for determining the legal basis for collecting, storing, combining, and contacting people using the output.
Avoid excessive collection, secure downloaded datasets, keep data only as long as necessary, and honor valid deletion or opt-out requests where applicable.
Support
If you encounter a reproducible problem, open an issue from the Actor's Apify page and include:
- the run ID
- a sanitized copy of the input
- the expected result
- the observed result
- whether the issue occurs consistently
Do not include API tokens, credentials, or confidential customer data.