Google Maps Scraper avatar

Google Maps Scraper

Pricing

from $2.70 / 1,000 results

Go to Apify Store
Google Maps Scraper

Google Maps Scraper

Extract business data from Google Maps at scale. Get names, addresses, phone numbers, websites, ratings, reviews, opening hours, popular times, photos, and 40+ data points per listing.

Pricing

from $2.70 / 1,000 results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

91

Total users

2

Monthly active users

7 days ago

Last modified

Share

Google Maps Scraper: Business Listings, Reviews & Location Data

Google Maps Scraper turns Google Maps into structured business data. Search by keyword, paste Google Maps links, or draw a custom area, then pull names, addresses, phone numbers, websites, ratings, opening hours, popular times and reviews for every matching place. Export to JSON, CSV or Excel, or read the results straight through the API.

Why This Scraper?

  • Two ways to find places. Free text search terms, or direct Google Maps place-page and search-result links, no manual URL building.
  • Full business profiles. Contact details, location, category, price level, opening hours, popular times, photos and "people also search for" in one record.
  • Reviews on demand. Turn on review extraction per run, with sort order, or skip it entirely for faster runs.
  • Area coverage. Draw a custom polygon and the actor builds a grid of searches across it, so you are not limited to Google's per-search result cap.
  • Built for schedules. Incremental mode returns only new and changed businesses on recurring runs, and a resumed run never re-scrapes a place it already collected.

Use Cases

  • Lead generation: build prospect lists with names, phone numbers, websites and categories for a market or neighborhood.
  • Local SEO and reputation tracking: monitor ratings, review counts and review text for your business and competitors over time.
  • Market and site research: map competitor density, categories, price levels and ratings for real estate, retail or franchise planning.
  • Data enrichment: attach verified addresses, coordinates and opening hours to an existing list of businesses.
  • Delivery and menu research: collect menu links and order/delivery platform links for restaurants in an area.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
placeId"ChIJN1t_tDeuEmsRUsoyG83frY4"
title"Example Coffee Roasters"
categoryName"Coffee shop"
address"100 Example St, San Francisco, CA 94102, USA"
street / city / state / postalCode / countryCodeAddress components parsed from address, when Google's format allows it
location{ "lat": 37.7763, "lng": -122.4158 }
plusCode"QHFJ+8R Hayes Valley, San Francisco, CA"
phone"+1 555 010 0100"
website"https://www.example.com"
totalScore4.5
reviewsCount1842
priceLevel"$$"
openingHours[{ "day": "Monday", "hours": "7 am to 6 pm" }, ...]
popularTimesHourly occupancy percent per day, when Google shows it for that place
imageUrlsPhoto URLs, up to the configured limit
peopleAlsoSearchRelated places Google shows on the same listing
menuUrl / orderLinksMenu link, and delivery platform links (Uber Eats, DoorDash, ...) when present
locatedInParent place, for a business inside a mall or airport
temporarilyClosed / permanentlyClosedClosure status flags
searchString / rank / isAdvertisementWhich search found this place, its position, and whether it was a sponsored slot
scrapedAt"2025-12-06T10:30:00.000Z"
reviewsReviewer name, rating, text, date and owner response, when Max Reviews Per Business is above 0
changeType / changedFields / firstSeenAt / lastSeenAtPresent only when Incremental mode is on: how this business changed since the last tracked run

How to Use

  1. Pick how to find places: free text search terms, or direct Google Maps links.
  2. Optionally narrow the area with a location string, coordinates, country/state/city/postal code, or a custom polygon, and set the map zoom.
  3. Set how many results, reviews and photos to collect per search, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Basic keyword search:

{
"searchStringsArray": ["coffee shops"],
"location": "Seattle, WA",
"maxResultsPerSearch": 50
}

Coordinate search with reviews:

{
"searchStringsArray": ["dentists"],
"lat": 41.8781,
"lng": -87.6298,
"zoom": 15,
"maxReviews": 20,
"reviewsSort": "newest"
}

Custom area grid search:

{
"searchStringsArray": ["hotels"],
"customGeolocation": {
"type": "Polygon",
"coordinates": [[[-122.5, 37.7], [-122.3, 37.7], [-122.3, 37.85], [-122.5, 37.85], [-122.5, 37.7]]]
},
"zoom": 16,
"maxResultsPerSearch": 200
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/google-maps-scraper").call(run_input={"searchStringsArray": ["coffee shops"], "location": "Seattle, WA"})
for business in client.dataset(run["defaultDatasetId"]).iterate_items():
print(business["title"], business.get("totalScore"))

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/google-maps-scraper').call({ searchStringsArray: ['coffee shops'], location: 'Seattle, WA' });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Grid search for large areas

Google Maps caps how many results a single search returns. Set customGeolocation to a GeoJSON Polygon or MultiPolygon and the actor generates a grid of search points across it based on zoom, so a large area is covered as many smaller searches instead of one capped one. A Point geometry is also accepted, but is treated as a single search location.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted run: paste its run ID and the actor skips every Place ID it already collected there, so you don't pay twice. The deprecated resumeRunId field still works the same way; if both are set, resumeFromRunId wins.
  • Incremental mode (incrementalMode) is for scheduled runs over the same search. Each business is classified NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless emitUnchanged is on), REAPPEARED, or EXPIRED (only after a run that fully re-walked the search, and only with emitExpired). stateKey names or shares the tracked baseline; leave it empty and the actor derives one from your search settings. With Incremental mode off, output is exactly as before.

Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape, the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each business, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
searchStringsArrayarray["restaurants"]Free text search terms.
startUrlsarray(none)Direct Google Maps place-page or search-result links to scrape.
locationstring"New York, NY"Location text appended to each search term.
latnumber(none)Latitude for a coordinate-based search (-90 to 90). Must be set together with lng.
lngnumber(none)Longitude for a coordinate-based search (-180 to 180). Must be set together with lat.
countrystring(none)Country used to build the search query when location is not set.
statestring(none)State or region used to build the search query when location is not set.
citystring(none)City used to build the search query when location is not set.
postalCodestring(none)Postal or ZIP code filter.
customGeolocationobject(none)GeoJSON Polygon or MultiPolygon boundary; the actor builds a grid of searches across it. A Point is accepted as a single search location.
zoominteger14Map zoom level (1 to 21). Higher values mean a smaller area per grid cell and more precise results.
maxResultsPerSearchinteger2Maximum results to extract per search term or grid point (up to 10,000).
maxReviewsinteger0Maximum reviews to extract per business. 0 skips review extraction.
maxImagesinteger10Maximum photo URLs to extract per business.
reviewsSortstringrelevantReview sort order: relevant, newest, highest, or lowest.
oneReviewPerRowbooleanfalseOutput one dataset row per review instead of one row per business, useful for CSV export.
skipClosedPlacesbooleanfalseSkip temporarily or permanently closed businesses.
languagestringenLanguage code for search results and extracted text.
maxConcurrencyinteger5Maximum number of pages processed in parallel (1 to 20).
proxyConfigurationobjectApify Proxy offConnection settings for all requests.
resumeFromRunIdstring(none)Run ID of a previous run to continue; already-scraped Place IDs are skipped.
resumeRunIdstring(none)Deprecated, use resumeFromRunId instead. Still honored for existing saved tasks; resumeFromRunId wins if both are set.
incrementalModebooleanfalseTurn on recurring monitoring of the same search, classifying each business as NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED across scheduled runs.
stateKeystring(none)Manually name the Incremental mode baseline. Leave empty to derive it automatically from your search settings.
emitUnchangedbooleanfalseAlso output businesses with no changes since the last run (bills and returns an extra row for each).
emitExpiredbooleanfalseAlso output a synthetic row for a previously tracked business no longer found, only after a run proves it fully re-scanned the search.
mcpConnectorsarray(none)Optional: send a summary of each business to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which item pages are created.
maxNotifyListingsinteger50Cap on items written to each connector per run.

Output Example

Sample shape: values are illustrative placeholders, not from a live record.

{
"placeId": "ChIJ49sQuK-AhYARM6U646SA12Y",
"title": "Example Coffee Roasters",
"url": "https://www.google.com/maps/place/Example-Coffee-Roasters/ChIJ49sQuK-AhYARM6U646SA12Y",
"categoryName": "Coffee shop",
"address": "100 Example St, San Francisco, CA 94102, USA",
"street": "100 Example St",
"city": "San Francisco",
"state": "CA",
"postalCode": "94102",
"countryCode": "US",
"location": { "lat": 37.7763, "lng": -122.4158 },
"plusCode": "QHFJ+8R Hayes Valley, San Francisco, CA",
"phone": "+1 555 010 0100",
"website": "https://www.example.com",
"totalScore": 4.5,
"reviewsCount": 1842,
"priceLevel": "$$",
"openingHours": [
{ "day": "Monday", "hours": "7 am to 6 pm" },
{ "day": "Tuesday", "hours": "7 am to 6 pm" }
],
"imageUrls": ["https://lh3.googleusercontent.com/example=w800-h600"],
"menuUrl": "https://www.example.com/menu",
"temporarilyClosed": false,
"permanentlyClosed": false,
"searchString": "coffee shops",
"rank": 3,
"isAdvertisement": false,
"scrapedAt": "2025-12-06T10:30:00.000Z",
"reviews": [
{
"reviewId": "review_0123456789abcdef",
"reviewerName": "Sample Reviewer",
"rating": 5,
"text": "Great coffee and atmosphere.",
"publishedAtDate": "2025-11-22T09:00:00.000Z"
}
]
}

Plan Requirement

The default connection works for most searches out of the box. For large grid searches across many polygon cells, or for high volumes of detail pages, switch Proxy Configuration to a residential group under Connection for steadier throughput. The Pricing tab shows the current rates.

FAQ

How much does it cost?

You pay per dataset row returned. Reviews are included inside each business row; if you turn on One Review Per Row, every review becomes its own row. The Pricing tab shows the current rates. Use Max Results Per Search to cap the cost of any run.

This actor collects only publicly available business listing data. You are responsible for how you use it: follow Google's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Reviews and photos may carry their authors' own rights.

Can I get only new or changed businesses on a schedule?

Yes. Schedule the actor from the Schedules tab against the same search and turn on Incremental mode. Each run then returns only new, updated, reappeared and expired businesses, and unchanged ones are not billed unless you turn on Emit unchanged businesses.

Why do I only get 2 results for a search term?

maxResultsPerSearch defaults to 2. Raise it, up to 10,000, to collect more results per search term or grid point. For very large areas, a customGeolocation grid search covers more ground than a single search term ever can.

Why did my run finish with an empty or partial dataset instead of failing?

The actor only stops the whole run for a configuration problem: no searchStringsArray or startUrls provided, lat set without lng (or the reverse), coordinates out of range, or turning on Incremental mode with resumeFromRunId against a search that already has tracked state. If Google Maps blocks or fails to load an individual search or business page, that one page is skipped and logged, and the run still finishes and returns whatever it did collect, which can be an empty dataset if every page was blocked. Run it again, or lower maxConcurrency, if you see this often.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

🔗 Want more leads data?

Pair this actor with these related scrapers from the same team:

📇 2GIS
From $1/1K. Extract business and place data from 2GIS.com at scale. Get names, addresses...
🧩 Yandex Maps Scraper
Scrape businesses and places from Yandex Maps by search term or URL for research, leads...
✈️ Naver Map Scraper
From $1/1K. Scrape Naver Map places by keyword or URL: names, categories, ratings...
📇 Herold.at Scraper
From $0.80/1K. Scrape Herold.at business listings across Austria into clean JSON. Extract...
📇 PagesJaunes FR
From $0.8/1K. Scrapes business listings from PagesJaunes.fr (French Yellow Pages)...
📇 BizBuySell Scraper
From $1.5/1K. Extract business-for-sale and franchise listings from bizbuysell.com with...

👉 Browse all abotapi scrapers

💬 Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.