# Google Maps Scraper - Fast Places & Leads Extractor (`mambo_melon/google-maps-scraper-fast`) Actor

Search Google Maps by keyword and location and get every place: name, category, full address, phone, website, rating, review count, opening hours, GPS, place ID. Goes past Google's ~120 result limit by splitting the area. Filter by website, rating, reviews.

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

## Pricing

from $1.25 / 1,000 places

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

## Google Maps Scraper (Fast Places & Leads Extractor)

Type a search term and a location, the way you would on Google Maps, and get back every place in a table: name, category, full address split into street, city, ZIP and state, phone, website, star rating, number of reviews, opening hours for the whole week, GPS coordinates, place ID and a link to the listing.

I wrote it because I needed lists of local businesses for my own outreach and kept running into the same two problems: Google stops showing results after about 120 places, and most scrapers charge extra for every field that makes a list usable (contacts, details, filters). This one doesn't open a browser. It talks to the same endpoint the Maps web app uses when you scroll the results list, so it's quick and cheap to run, and everything below comes in one price.

### What a result looks like

Real output from a run for "coffee shop" in Portland, OR (business name and contacts changed):

```json
{
  "title": "Example Coffee",
  "categoryName": "Coffee shop",
  "categories": ["Coffee shop", "Bakery", "Cafe"],
  "address": "1100 SE Grand Ave, Portland, OR 97214",
  "street": "1100 SE Grand Ave",
  "neighborhood": "Southeast Portland",
  "city": "Portland",
  "postalCode": "97214",
  "state": "Oregon",
  "countryCode": "US",
  "phone": "(503) 555-0142",
  "phoneUnformatted": "+15035550142",
  "website": "https://www.example-coffee.com/",
  "domain": "example-coffee.com",
  "totalScore": 4.8,
  "reviewsCount": 267,
  "latitude": 45.514786,
  "longitude": -122.6602143,
  "placeId": "ChIJF-hlsN0LlVQRYW3R9m8tIVg",
  "cid": "6350406908474649953",
  "url": "https://www.google.com/maps/search/?api=1&query=Example+Coffee&query_place_id=ChIJF-hlsN0LlVQRYW3R9m8tIVg",
  "openingHours": [
    { "day": "Monday", "hours": "9 AM–5 PM" },
    { "day": "Tuesday", "hours": "9 AM–5 PM" },
    "..."
  ],
  "closedStatus": null,
  "timezone": "America/Los_Angeles",
  "bookingLinks": [],
  "searchString": "coffee shop",
  "location": "Portland, OR",
  "rank": 2
}
```

Every row has the same fields, with `null` where Google has nothing (a business without a website, a place with no reviews yet), so CSV and Excel exports line up. The **Places** view in the dataset shows the short version; **Contacts** shows phone, website and address columns only.

### Getting more than 120 places

Google shows roughly 120 to 200 places for one search and then stops, no matter how big the city is. When that happens and you asked for more, the scraper takes the map area Google uses for your location, splits it into four smaller views, searches each one, and keeps splitting where a view is still full. Places found twice are dropped, and places that fall outside the area you searched are left out.

In my tests from the Apify cloud, 500 dentists in Berlin took 27 seconds and about 1,200 places across four searches took 80 seconds. Turn off `deepSearch` if you only want the first page of results Google would show a person.

### Input

| Field | What it does | Default |
|---|---|---|
| `searchTerms` | What to search for: `dentist`, `coffee shop`, `roofing contractor`... Each term runs in each location. | required |
| `locations` | `Austin, TX`, `Manchester, UK`, `Brooklyn, NY`, a ZIP code. Leave empty if the place is already in the search term. | |
| `maxPlacesPerSearch` | Limit per term and location | 100 |
| `deepSearch` | Go past Google's ~120 limit by splitting the area | on |
| `websiteFilter` | `all`, `withWebsite`, or `withoutWebsite` (good for selling websites) | all |
| `minRating` | Skip places rated below this, e.g. `4.0` | |
| `minReviews` | Skip places with fewer reviews | |
| `skipClosedPlaces` | Leave out places marked permanently closed | on |
| `language` | Language of categories and hours, e.g. `en`, `de`, `es` | en |
| `countryCode` | Google country, e.g. `us`, `gb`, `de` | us |

Places skipped by a filter are not charged. If the same place turns up for two of your search terms in one run, it's returned and charged once.

### Pricing

You pay per place returned, and that's it: contacts, opening hours, coordinates, categories and the filters are all included. There are no separate charges for details or for using a filter.

### FAQ

**Why are some phone numbers or websites empty?**
Because the business didn't add them to its Google profile. Service businesses like plumbers often hide their street address too, so `street` and `city` can be empty while the phone is there.

**Does it get reviews or emails?**
No. It returns what the Google Maps listing shows: the rating, the review count and a link to the reviews. If you need emails and a check of each business's website, [Local Business Leads with Website Audit](https://apify.com/mambo_melon/local-leads-website-audit) does that on top of a Maps search.

**Can I search a whole state or country?**
You can, but Google treats a state as one very large map view, so you'll get the most prominent places spread thin. For full coverage, list the cities you care about in `locations`.

**Some searches return fewer places than I asked for.**
That's usually all there is. A narrow term in a small town might have 40 matches, and strict filters like `withoutWebsite` skip most places. To keep a run from scanning an entire metro area for a handful of matches, each search stops after a fixed number of requests.

### Notes

Only public Google Maps listings are read, no login and no browser. If something comes back wrong for a search, open an issue with the input you used and I'll look at it.

Want to check which of these businesses need a better website? [Website Audit & Lead Scorer](https://apify.com/mambo_melon/website-audit-lead-scorer) takes the `website` column straight from this dataset.

# Actor input Schema

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

What you'd type into Google Maps, e.g. 'dentist', 'coffee shop', 'roofing contractor'. Each term is searched in each location.

## `locations` (type: `array`):

Cities, neighborhoods, ZIP codes or regions, e.g. 'Austin, TX', 'Manchester, UK', '10001'. Leave empty if the location is already in the search term.

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

Limit for each term + location pair. Google shows about 120 places per search; above that the area is split into smaller map views and searched again.

## `deepSearch` (type: `boolean`):

When a search hits Google's limit, split the area into smaller tiles and keep collecting. Turn off to get only the first results Google shows.

## `websiteFilter` (type: `string`):

Keep only places with a website, or only places without one (handy for web design leads). Skipped places are not charged.

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

Skip places rated below this, e.g. 4.0. Leave empty to keep all.

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

Skip places with fewer reviews. Leave empty to keep all.

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

Leave out places Google marks as permanently closed.

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

Language for categories and opening hours, e.g. en, de, es, fr.

## `countryCode` (type: `string`):

Two-letter country code Google should use, e.g. us, gb, de.

## Actor input object example

```json
{
  "searchTerms": [
    "dentist"
  ],
  "locations": [
    "Austin, TX"
  ],
  "maxPlacesPerSearch": 100,
  "deepSearch": true,
  "websiteFilter": "all",
  "skipClosedPlaces": true,
  "language": "en",
  "countryCode": "us"
}
```

# Actor output Schema

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

No description

## `contacts` (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"
    ],
    "locations": [
        "Austin, TX"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mambo_melon/google-maps-scraper-fast").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"],
    "locations": ["Austin, TX"],
}

# Run the Actor and wait for it to finish
run = client.actor("mambo_melon/google-maps-scraper-fast").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 '{
  "searchTerms": [
    "dentist"
  ],
  "locations": [
    "Austin, TX"
  ]
}' |
apify call mambo_melon/google-maps-scraper-fast --silent --output-dataset

```

## MCP server setup

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

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/o6c1B7quguMFVuauD/builds/K677cukoRubBDiqhw/openapi.json
