# Google Maps Scraper - Places, Phone, Website & Reviews (`flash_scraper/google-maps-places`) Actor

Scrape Google Maps places by search term and location: name, star rating, review count, category, address, opening hours, and optionally phone and website. Uses a real browser because Maps renders results client-side. Export CSV/JSON/Excel. No API key.

- **URL**: https://apify.com/flash\_scraper/google-maps-places.md
- **Developed by:** [Flash Scrape](https://apify.com/flash_scraper) (community)
- **Categories:** Lead generation, Business, Other
- **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.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Maps Places — Ratings, Reviews & Contacts

**Scrape Google Maps by search term and location.** Give it `dentist` + `Austin, TX` and get back each place's name, star rating, review count, category, street address, opening hours — and optionally **phone number and website**, which is what turns a directory into a contactable lead list.

No API key. No Google Cloud billing account.

***

### Why this uses a browser

Google Maps serves **no place data at all** to an ordinary HTTP request. Measured: the search page returns ~200 kb containing zero business names, zero phones and zero addresses, because results render client-side. So this Actor drives a real anti-detect browser instead. That is slower and heavier than a plain HTTP scraper, and priced accordingly — but it is the only way to get this data without a paid Places API key.

### What you get per place

| Field | Notes |
|---|---|
| `name` | Business name |
| `category` | Google's own category, e.g. `Plumber`, `Dentist` |
| `rating` | 0–5 stars |
| `reviews_count` | Total review count |
| `address` | Street address as shown |
| `hours_summary` | e.g. `Open · Closes 8 PM`, `Closed · Opens 8 AM Mon` |
| `is_open_now` | Boolean, derived from the hours line |
| `phone` | **Requires `fetchContactDetails`** |
| `website` | **Requires `fetchContactDetails`** — Google redirect stripped |
| `plus_code`, `price_level` | When shown |
| `place_id`, `maps_url` | Stable identifiers for de-duplicating across runs |
| `search_term`, `search_location`, `scraped_at` | Provenance |

Verified on a live run: `plumber` in `Denver, CO` returned **6/6 populated** for name, category, address, rating, review count, phone, website, hours and place\_id — with counts like 17,657 and 9,042.

### Input

| Field | Type | Notes |
|---|---|---|
| `searchTerms` | array | e.g. `["dentist", "orthodontist"]` — each searched separately |
| `location` | string | e.g. `"Austin, TX"`. Combined as `<term> in <location>` |
| `maxPlaces` | integer | Hard cap per run |
| `scrollDepth` | integer | How many times to scroll the feed — **this is what controls volume** |
| `fetchContactDetails` | boolean | Adds phone + website; one extra page load per place, charged separately |
| `minRating`, `minReviews` | — | `0` = no filter |
| `onlyWithWebsite` | boolean | Needs `fetchContactDetails` on |
| `proxyConfiguration` | object | Recommended; the datacenter group is enough |

```json
{
  "searchTerms": ["plumber"],
  "location": "Denver, CO",
  "maxPlaces": 60,
  "scrollDepth": 8,
  "fetchContactDetails": true,
  "minReviews": 20
}
```

### Honest limits

- **Volume comes from scrolling, not pagination.** A fresh search shows ~7 places; scrolling grows it to ~25–30 per term. Raising `scrollDepth` beyond the point where no new places appear does nothing — the Actor detects that and stops early. **To go wider, add more search terms or narrower locations**, not a bigger `scrollDepth`.
- **`reviews_count` is often missing from the results list.** Many cards expose only `4.8 stars` with no count anywhere in the markup. The Actor recovers it from the place panel, so **turn on `fetchContactDetails` if you need review counts reliably**. Without it, expect gaps.
- **`phone` and `website` are never in the results list** — they exist only on the place panel, hence the separate flag and charge.
- **Rated ≠ reviewed.** A place can show a rating on very few reviews; filter with `minReviews`, not `minRating` alone, to find genuinely established businesses.
- **This is a browser Actor.** It needs ~4 GB memory (already set as the default) and is markedly slower per result than an HTTP scraper. A 1 GB run is killed by the browser's own memory use.
- **If Google serves a consent or bot-check page**, the Actor stops and reports how many places went unscraped rather than returning a short list that looks complete. You are only charged for places that returned data.

### Use cases

- **Local lead generation** — filter by category, rating and review count, then pull phone and website for outreach.
- **Competitor mapping** — every rival in a metro with their ratings and review volume side by side.
- **Franchise and territory research** — run one term across several cities to compare density and quality.
- **Review-volume benchmarking** — `reviews_count` separates established players from new entrants far better than rating alone.

### Pricing

Pay per result: **per place delivered**, plus a smaller **contact-detail** charge only for places whose panel was opened for phone and website. Places removed by your filters are **not** charged.

### FAQ

**Do I need a Google API key?** No. The official Places API requires a billing account; this does not.

**Why is `reviews_count` empty on some rows?** Google omits it from the results list for many places. Enable `fetchContactDetails` and it is read from the place panel instead.

**Can I get individual review text?** Not in this Actor — it returns the rating and the count, not review bodies.

**Why is it slower than your other scrapers?** It runs a real browser, because Maps has no server-rendered data to parse.

# Actor input Schema

## `searchTerms` (type: `array`):

What to look for, e.g. \['dentist', 'plumber']. Each term is searched separately.

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

City, region or area to search in, e.g. 'Austin, TX'. Combined with each search term as '<term> in <location>'. Leave blank to let Google decide.

## `maxPlaces` (type: `integer`):

Hard cap per run. Google's feed yields roughly 20-60 places per search term before it stops loading more.

## `scrollDepth` (type: `integer`):

How many times to scroll the results list. Volume on Google Maps comes from scrolling, not pagination: a fresh search shows about 7 places and scrolling grows it to roughly 28+. Stops early once no new places appear.

## `fetchContactDetails` (type: `boolean`):

Phone number and website are NOT in the results list; getting them needs one extra page load per place, so this is slower and charged separately. Turn on when you need contactable leads rather than a directory.

## `minRating` (type: `string`):

e.g. 4.0. Blank or 0 = no filter. Places with no rating at all are treated as 0.

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

Filters out places with too few reviews to judge. 0 = no filter.

## `onlyWithWebsite` (type: `boolean`):

Requires 'Also fetch phone and website' to be on, since the website is only visible on the place panel.

## `proxyConfiguration` (type: `object`):

Recommended. Google rate-limits repeated requests from one IP and may serve a consent page instead of results. The standard datacenter group is enough.

## Actor input object example

```json
{
  "searchTerms": [
    "dentist"
  ],
  "location": "Austin, TX",
  "maxPlaces": 60,
  "scrollDepth": 6,
  "fetchContactDetails": false,
  "minRating": "0",
  "minReviews": 0,
  "onlyWithWebsite": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "searchTerms": [
        "dentist"
    ],
    "location": "Austin, TX",
    "maxPlaces": 60,
    "scrollDepth": 6,
    "fetchContactDetails": false,
    "minRating": "0",
    "minReviews": 0,
    "onlyWithWebsite": false,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("flash_scraper/google-maps-places").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 = {
    "searchTerms": ["dentist"],
    "location": "Austin, TX",
    "maxPlaces": 60,
    "scrollDepth": 6,
    "fetchContactDetails": False,
    "minRating": "0",
    "minReviews": 0,
    "onlyWithWebsite": False,
    "proxyConfiguration": { "useApifyProxy": True },
}

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

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

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

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "dentist"
  ],
  "location": "Austin, TX",
  "maxPlaces": 60,
  "scrollDepth": 6,
  "fetchContactDetails": false,
  "minRating": "0",
  "minReviews": 0,
  "onlyWithWebsite": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call flash_scraper/google-maps-places --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=flash_scraper/google-maps-places",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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