# Google Maps Places Scraper (`barefoot_grade/google-maps-places-scraper`) Actor

Collect places from Google Maps searches: name, rating, review count, address, categories, coordinates, website, phone, opening hours and Maps link, one row per place. Search by term and location or paste a Maps search link. Failed searches are reported, not charged.

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

## Pricing

from $1.00 / 1,000 results

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/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 Places Scraper

Turn any Google Maps search into a clean list of places. Type what you are looking for and where (for example "coffee shop" in "Austin, TX"), or paste a Google Maps search link, and every place in the results becomes one row: name, star rating and review count, full address with city, postal code and country, categories, coordinates, website, phone number, weekly opening hours and a link that opens the place on Google Maps.

Results are read well past the first 20 places, up to the cap you set, so one search can return a whole neighborhood's dentists, a city's coffee shops or every hotel near a map point. Places that appear in more than one of your searches are returned once.

### Use cases

- **Lead lists**: local businesses by category and city, with website and phone.
- **Market mapping**: how many competitors sit in an area, and how they are rated.
- **Location data**: coordinates, addresses and opening hours for a set of places.
- **Monitoring**: re-run the same searches to track ratings and review counts over time.

### Quick Start

```json
{
  "searchQueries": ["coffee shop"],
  "location": "Austin, TX",
  "maxPlacesPerSearch": 40,
  "maxPlaces": 100
}
```

Several search terms run as separate searches in the same location. To search around an exact point instead, give `latitude`, `longitude` and a `zoom` level, or paste a Maps link such as `https://www.google.com/maps/search/pizza/@40.7128,-74.0060,14z`.

### Radius search (no proxy required)

Give `lat`, `lng` and a positive `radiusMeters` to bias the map viewport and keep only places inside the circle. `latitude`/`longitude` also work. Zoom is selected from the radius unless you explicitly set it. This applies to search links too. Rows include `distanceMeters` (haversine distance from the centre); places without coordinates are dropped before caps and billing. Text-only searches are unchanged. Google ranks and limits results, so this is not an exhaustive census.

```json
{
  "searchQueries": ["supermercado"],
  "lat": -12.1211,
  "lng": -77.0297,
  "radiusMeters": 1500,
  "language": "es",
  "countryCode": "pe"
}
```

### Input

| Input | Type | Default | Meaning |
| --- | --- | --- | --- |
| `searchQueries` | array | `[]` | What to look for, as you would type it into Google Maps. Each term is one search. |
| `location` | string | `""` | Where to search (city, neighborhood or postal code). Added to every search term. |
| `searchUrls` | array | `[]` | Google Maps search links (`google.com/maps/search/...`), including ones with a map point. Each link is one search. |
| `maxPlacesPerSearch` | integer | `40` | Stop each search after this many places. Google Maps lists up to a few hundred places per search. |
| `maxPlaces` | integer | `100` | Total cap on place rows across all searches, after removing repeats. |
| `latitude`, `longitude` | string | empty | Optional map point to center the searches on. Give both. |
| `lat`, `lng` | number | empty | Numeric aliases for `latitude`/`longitude`; aliases must agree if both forms are provided. |
| `radiusMeters` | number | empty | Positive radius in metres. Requires a centre; filters results and adds `distanceMeters`. |
| `zoom` | integer | `14` | Zoom level for the map point, from 3 (continent) to 21 (building). |
| `language` | string | `en` | Language for names, categories and opening hours (`en`, `de`, `es`, `pt-BR`, ...). |
| `countryCode` | string | `us` | The region Google Maps should favor (`us`, `gb`, `de`, ...). |
| `proxyConfiguration` | object | empty | Optional. Route requests through Apify Proxy or your own proxies; leave empty for the default connection. |

### Example queries

- `{"searchQueries": ["dentist", "orthodontist"], "location": "Chicago, IL", "maxPlacesPerSearch": 100}`
- `{"searchQueries": ["Restaurant"], "location": "Berlin", "language": "de", "countryCode": "de"}`
- `{"searchQueries": ["hotel"], "latitude": "51.5072", "longitude": "-0.1276", "zoom": 13, "countryCode": "gb"}`
- `{"searchUrls": ["https://www.google.com/maps/search/pizza/@40.7128,-74.0060,14z"]}`

### What it returns

The dataset contains one row per place:

| Field | Meaning |
| --- | --- |
| `kind` | `place` for every dataset row. |
| `placeId`, `cid`, `featureId` | Google's identifiers for the place (place ID, customer ID and Maps feature ID). |
| `name` | Place name. |
| `rating`, `reviewCount` | Average star rating and number of reviews. |
| `priceLevel` | Price level or range as Google shows it, when it shows one. |
| `categories`, `primaryCategory` | Every category Google lists, and the first one. |
| `address` | Full formatted address. |
| `street`, `neighborhood`, `city`, `postalCode`, `state`, `countryCode` | Address parts. |
| `latitude`, `longitude`, `timezone` | Location and local time zone. |
| `distanceMeters` | Distance from the requested centre in metres (radius mode only). |
| `website` | The place's website. |
| `phone`, `phoneInternational` | Phone number in local and international format. |
| `openingHours` | One entry per weekday with that day's hours, as shown for the current week. |
| `description` | Short summary of the place, when Google has one. |
| `imageUrl` | Main photo thumbnail. |
| `mapsUrl` | Link that opens the place on Google Maps. |
| `searchQuery`, `searchUrl`, `rank` | The search the row came from and the place's position in its results. |
| `scrapedAt` | Collection time (UTC, ISO 8601). |
| `error` | Always `null` in the dataset. Failed searches are reported in the run summary instead. |

The run summary (`OUTPUT`) reports `places` (rows delivered), one entry per search in `searches` with its place count, and any failed searches in `searchErrors` with a short code and message (for example `RATE_LIMITED` or `NO_RESULTS`).

### Output example

```json
{
  "kind": "place",
  "placeId": "ChIJG-gJw2vKRIYROWi2uwOp8QE",
  "cid": "140078896924485689",
  "featureId": "0x8644ca6bc309e81b:0x1f1a903bbb66839",
  "name": "Epoch Coffee",
  "rating": 4.5,
  "reviewCount": 2538,
  "priceLevel": null,
  "categories": [
    "Coffee shop"
  ],
  "primaryCategory": "Coffee shop",
  "address": "221 W N Loop Blvd, Austin, TX 78751",
  "street": "221 W N Loop Blvd",
  "neighborhood": "North Loop",
  "city": "Austin",
  "postalCode": "78751",
  "state": "Texas",
  "countryCode": "US",
  "latitude": 30.3186037,
  "longitude": -97.7245402,
  "timezone": "America/Chicago",
  "website": "http://www.epochcoffee.com/",
  "phone": "(512) 454-3762",
  "phoneInternational": "+15124543762",
  "openingHours": [
    {
      "day": "Monday",
      "hours": "12 AM–11:30 PM"
    },
    {
      "day": "Tuesday",
      "hours": "Open 24 hours"
    },
    {
      "day": "Wednesday",
      "hours": "Open 24 hours"
    },
    {
      "day": "Thursday",
      "hours": "Open 24 hours"
    },
    {
      "day": "Friday",
      "hours": "Open 24 hours"
    },
    {
      "day": "Saturday",
      "hours": "Open 24 hours"
    },
    {
      "day": "Sunday",
      "hours": "Open 24 hours"
    }
  ],
  "description": "Cool, vibrant small-chain cafe featuring nibbles, tea & carefully brewed espresso drinks.",
  "imageUrl": "https://lh3.googleusercontent.com/grass-cs/AABkmLemmlApZqzw26-EYyEdrzH6YCtaCFcmgVA98rWVxjWxMZoqyvLjtYX0ouSvthwfZmrQX3hsGHHJrXPZcqDTNe-lmYbWofdrJGYiCUCjCKa79NjqGTD402iy2R6abf2BAOPGyB9z=w114-h86-k-no",
  "mapsUrl": "https://www.google.com/maps/search/?api=1&query=Epoch+Coffee&query_place_id=ChIJG-gJw2vKRIYROWi2uwOp8QE",
  "searchQuery": "coffee shop",
  "searchUrl": "https://www.google.com/maps/search/coffee%20shop%20in%20Austin%2C%20TX?hl=en&gl=us",
  "rank": 2,
  "scrapedAt": "2026-10-19T22:34:00Z",
  "error": null
}
```

### Price

**$0.001 per place** delivered, plus **$0.005 per run start**. The run-start event is charged per GB of memory; the default 512 MB run is one start event. The start is charged even if the run saves no results. Failed searches are not charged, and a place found by two of your searches is charged once. Platform usage is included in these prices.

### Good to know

- Reviews themselves (review text and authors) are not included; `rating` and `reviewCount` are.
- Google Maps shows a limited set of details to visitors who are not signed in. Popular times, the full "About" tab and photo galleries are not part of the output.
- Opening hours are the hours Google shows for the current week, so holiday hours appear when Google lists them.
- A search that names one specific place (for example a business name and street address) returns just that place.
- If Google Maps temporarily limits requests, the run retries with growing pauses and reports any search it could not finish in `OUTPUT.searchErrors`; places already collected are kept.

# Actor input Schema

## `searchQueries` (type: `array`):

What to look for, as you would type it into Google Maps (for example "coffee shop" or "dentist"). Each term is one search.

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

Where to search, such as a city, neighborhood or postal code (for example "Austin, TX"). It is added to every search term. Leave empty to rely on the search terms or the map point below.

## `searchUrls` (type: `array`):

Optional Google Maps search links (google.com/maps/search/...), including ones with a map point such as /@30.27,-97.74,14z. Each link is one search.

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

Stop each search after this many places. Google Maps lists up to a few hundred places per search; results are read 20 at a time.

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

Total cap on place rows across every search, after removing places already returned by an earlier search.

## `latitude` (type: `string`):

Optional. Center the searches on this latitude (use together with longitude), for example 30.2672.

## `longitude` (type: `string`):

Optional. Center the searches on this longitude (use together with latitude), for example -97.7431.

## `lat` (type: `number`):

Optional numeric alias for latitude; give together with lng. If both aliases are supplied they must agree.

## `lng` (type: `number`):

Optional numeric alias for longitude; give together with lat.

## `radiusMeters` (type: `number`):

Optional positive radius around lat/lng or latitude/longitude. Biases the map viewport and drops places outside the circle or without coordinates. Automatically selects zoom unless explicitly set.

## `zoom` (type: `integer`):

Zoom level for the map point, from 3 (continent) to 21 (building). 14 is about a neighborhood.

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

Language code for place names, categories and opening hours, such as en, de, es or pt-BR.

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

Two-letter country code for the region Google Maps should favor, such as us, gb or de.

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

Optional. Route requests through Apify Proxy (automatic group) or your own proxies. Leave empty for the default connection.

## Actor input object example

```json
{
  "searchQueries": [
    "coffee shop"
  ],
  "location": "Austin, TX",
  "searchUrls": [],
  "maxPlacesPerSearch": 40,
  "maxPlaces": 100,
  "zoom": 14,
  "language": "en",
  "countryCode": "us"
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "searchQueries": [
        "coffee shop"
    ],
    "location": "Austin, TX",
    "searchUrls": [],
    "maxPlacesPerSearch": 40,
    "maxPlaces": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("barefoot_grade/google-maps-places-scraper").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 = {
    "searchQueries": ["coffee shop"],
    "location": "Austin, TX",
    "searchUrls": [],
    "maxPlacesPerSearch": 40,
    "maxPlaces": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("barefoot_grade/google-maps-places-scraper").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 '{
  "searchQueries": [
    "coffee shop"
  ],
  "location": "Austin, TX",
  "searchUrls": [],
  "maxPlacesPerSearch": 40,
  "maxPlaces": 100
}' |
apify call barefoot_grade/google-maps-places-scraper --silent --output-dataset

```

## MCP server setup

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

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/bMBRG0WSyAFuRRd17/builds/cfXGad7DF3rp9iyqa/openapi.json
