# Google Maps Scraper Pro: Reviews, Photos & Emails (`tidyharvest/google-maps-scraper-pro`) Actor

Built to beat Google Maps Scraper: on the same 100 places, the same star breakdown, popular times, review topics, owner text and hotel details, faster; 2.4x the Leeds plumbers in a whole-city run; 98% of results in the city you asked for (theirs 77%). Every add-on at 70% of its price.

- **URL**: https://apify.com/tidyharvest/google-maps-scraper-pro.md
- **Developed by:** [TidyHarvest](https://apify.com/tidyharvest) (community)
- **Categories:** Lead generation, Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

./README.md

# Actor input Schema

## `searches` (type: `array`):

What you would type into Google Maps, one per line: `coffee shops`, `plumbers`, `wine bars in San Francisco`. For a list of known businesses, one per line as `Name, street, city` (or paste Google Maps place links; for exact place ids use Place IDs below) and set Max places per search to 1: each line gets its best match, labelled by how well name and street agree, and a line with no confident match comes back as a free `lookupMatch: none` row. With a Location below, write just the category (`coffee shops`).

## `placeIds` (type: `array`):

Exact places, one per line: a placeId (`ChIJ...`), a CID, or a Google Maps place link. Each comes back as that exact place. Use with or instead of Searches.

## `startUrls` (type: `array`):

Google Maps links, one per line: a place link returns that place; a search link (`google.com/maps/search/coffee/@37.76,-122.42,14z`) runs that search on that part of the map.

## `location` (type: `string`):

A city, district or region (`Austin, TX`, `Brooklyn`, `Bruges, Belgium`). Each search then covers the whole area, past Google Maps' ~120-results-per-search limit. Places outside the area's boundary are dropped and not charged.

## `customGeolocation` (type: `object`):

Instead of a Location: a GeoJSON `Polygon` or `MultiPolygon` (longitude, latitude order), a `Point` with `radiusKm`, or a bounding box `[south, west, north, east]`. Each search then covers that shape, and places outside it are dropped and not charged.

## `postalCodes` (type: `array`):

Run each search once per postal code (`80302`, `LS7`, `75011`). Set Country to the codes' country.

## `city` (type: `string`):

Instead of Location: city, with County and State below if needed (set Country too).

## `county` (type: `string`):

Optional, with City or State.

## `state` (type: `string`):

Optional, with City or County.

## `splitArea` (type: `boolean`):

With a Location: keep searching until the whole area is covered or the search budget is used. Off = one search of up to ~120 places centred on the location.

## `maxCellsPerSearch` (type: `integer`):

Search budget per category in whole-area mode. The run stops earlier when the area is covered. 60 covers one category in a city of ~100k; raise it for large cities or broad categories like restaurants.

## `broadMatch` (type: `boolean`):

Also keep places whose main category is close to your search (Gas engineer for plumbers). More places, a few less exact; off keeps results strictly on-category.

## `maxPlacesPerSearch` (type: `integer`):

Cap per search. Default 60 for a normal search (Google stops at ~120); no cap in whole-area mode unless you set one. 1 = lookup mode for lists of known businesses (see Searches).

## `latitude` (type: `number`):

Center the search here. Use with Longitude and Radius.

## `longitude` (type: `number`):

Center the search here.

## `radiusMeters` (type: `integer`):

Search area around the coordinates. Default 10,000.

## `strictLocation` (type: `boolean`):

Google sometimes mixes in places from another city with the same name (Glasgow, Delaware for `electricians in Glasgow`) or another country. On: those are dropped and not charged (counted in the run's SUMMARY). Service-area businesses with no public address are kept.

## `scrapePlaceDetails` (type: `boolean`):

Open each place's own page for: the 1-5 star breakdown, popular times by hour, review topics with counts, the business's own description and posts, owner, "located in", order and booking links, hotel class, amenities and nightly price, and the total photo count. Add-on: $1.40 per 1,000 places (charged only when the page answers). Reviews and photos below are priced separately.

## `maxReviews` (type: `integer`):

0-8: the reviews Google shows on the place's page, with text, stars, date, reviewer, owner reply and the diner/hotel answers. $0.35 per 1,000 reviews.

## `reviewsSort` (type: `string`):

Order of the reviews returned (of the ones Google shows on the place's page).

## `reviewsStartDate` (type: `string`):

A date (`2026-05-03`) or a period (`8 days`, `3 months`, `1 year`).

## `reviewsFilterString` (type: `string`):

Keep reviews containing any of these words (space or comma separated).

## `reviewsOrigin` (type: `string`):

Hotels also show partner reviews.

## `scrapeReviewsPersonalData` (type: `boolean`):

Reviewer name, id, profile link and photo, and the review link. Off: reviews come without them.

## `maxImages` (type: `integer`):

0-20 photo links per place (with size), Street View last. $0.35 per 1,000 photos; Street View thumbnails are free.

## `scrapeImageAuthors` (type: `boolean`):

Add each photo's author and date (slower: about a second per photo). Included in the photo price.

## `includeContacts` (type: `boolean`):

Read each place's own website (contact, about and team pages) for emails (typed: company inbox, named person, or other), extra phone numbers and Instagram, Facebook, TikTok, X, YouTube and LinkedIn links. Add-on: $1.40 per 1,000 places whose website answers (no website, dead, parked or blocked sites are free).

## `checkEmails` (type: `boolean`):

With website contacts: check each email's syntax, mail server (MX), disposable, role and free-mail status. $0.30 per 1,000 emails checked.

## `keywords` (type: `array`):

Keep a place only if its name, categories or description contains one of these.

## `minRating` (type: `number`):

Keep places rated at least this (0-5).

## `minReviews` (type: `integer`):

Keep places with at least this many reviews.

## `requireWebsite` (type: `boolean`):

Drop places that list no website.

## `website` (type: `string`):

Keep places by whether they list a website. Free (no filter fee).

## `categoryFilterWords` (type: `array`):

Keep only places with one of these categories (`dentist`, `italian restaurant`): matched against every category Google lists for the place. Free.

## `searchMatching` (type: `string`):

Keep places whose name contains, or equals, the search term (the part before `in <place>`). Free.

## `skipClosedPlaces` (type: `boolean`):

Leave out places Google marks as permanently closed (not charged). Off: they are returned with `permanentlyClosed: true`.

## `language` (type: `string`):

Result language code, for example `en`, `es`, `de`.

## `country` (type: `string`):

Two-letter country code that biases results, for example `us`, `gb`, `mx`.

## `parallelSessions` (type: `integer`):

How many connections work at once. More is faster; 1 is the slowest and steadiest.

## `maxItems` (type: `integer`):

Hard cap on results for the whole run (also caps your cost). 0 or empty = no limit.

## `dedupeAcrossSearches` (type: `boolean`):

Return each place once per run. Turn off when you look up a list of businesses and want one row per input line, even for duplicates.

## `skipPlaceIds` (type: `array`):

placeId, fid or cid values to leave out (not charged). For scheduled runs that should return only new places.

## `skipDatasetIds` (type: `array`):

Dataset ids (or dataset URLs) of earlier runs of this actor: every place in them is skipped and not charged.

## Actor input object example

```json
{
  "searches": [
    "wine bars in San Francisco"
  ],
  "splitArea": true,
  "maxCellsPerSearch": 60,
  "broadMatch": false,
  "strictLocation": true,
  "scrapePlaceDetails": false,
  "maxReviews": 0,
  "reviewsSort": "mostRelevant",
  "reviewsOrigin": "all",
  "scrapeReviewsPersonalData": true,
  "maxImages": 0,
  "scrapeImageAuthors": false,
  "includeContacts": false,
  "checkEmails": false,
  "requireWebsite": false,
  "website": "allPlaces",
  "searchMatching": "all",
  "skipClosedPlaces": false,
  "language": "en",
  "country": "us",
  "parallelSessions": 4,
  "dedupeAcrossSearches": true
}
```

# Actor output Schema

## `places` (type: `string`):

One item per place.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searches": [
        "wine bars in San Francisco"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidyharvest/google-maps-scraper-pro").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "searches": ["wine bars in San Francisco"] }

# Run the Actor and wait for it to finish
run = client.actor("tidyharvest/google-maps-scraper-pro").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searches": [
    "wine bars in San Francisco"
  ]
}' |
apify call tidyharvest/google-maps-scraper-pro --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tidyharvest/google-maps-scraper-pro"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/dNkhOSh5wiL4ABgJp/builds/jcpiXQYDcoYnNfjsx/openapi.json
