# Google Maps Scraper — Places, Leads & Contact Data (`buff_pineapple/google-maps-scraper`) Actor

Scrape Google Maps places by search query. Returns name, full address, latitude/longitude, phone, website, rating, review count, category, price level, neighborhood, timezone, place ID and CID. HTTP-only — no browser, fast and cheap.

- **URL**: https://apify.com/buff\_pineapple/google-maps-scraper.md
- **Developed by:** [yossef Nagy](https://apify.com/buff_pineapple) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 84 total users, 46 monthly users, 62.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Scraper — Places, Leads, Reviews & Contact Data

Extract business data from Google Maps at scale — **names, addresses, phone numbers, websites, ratings, reviews, photos, opening hours, amenities, coordinates and more** — for any type of business in any location. No browser required: the Actor talks to Google Maps' internal endpoints directly over HTTP, so it's fast and cheap.

It also ships powerful, optional layers: **precise targeting** (batch queries, map URLs, or a drawn area), **deep reviews**, **complete place data**, plus experimental **lead enrichment** (emails, socials, people/contacts) and **ad intelligence** (is the business advertising on Meta / Google right now?).

---

### What does it do?

1. **Searches Google Maps** for your query and covers the whole area with a **grid search**, finding businesses that a single search page misses.
2. **Extracts a clean record** for every business — the full place profile.
3. **Optionally enriches** each business with deeper place data, full reviews, website contact data, the people who work there, and live ad-spend signals.

---

### Features

- 🗺️ **Comprehensive place data** — name, address, phone, website, rating, review count, category list, coordinates, opening hours, price level, **photos, amenities, Plus Code, permanently-closed status**.
- 🎯 **Precise targeting** — search by a plain query, a **batch of queries**, **Google Maps URLs**, or a **custom area** (lat/lng + radius, or a GeoJSON polygon).
- ⭐ **Deep reviews** — review text, rating, date, author, **owner responses, reviewer stats, language, review photos**, plus **rating / keyword filters**.
- 📩 **Lead enrichment (experimental)** — emails (MX-validated) and social profiles harvested from each business's own website.
- 👤 **People / contacts (experimental)** — the actual people at a business with their own name, title, email, phone and LinkedIn.
- 📣 **Ad intelligence (experimental)** — detect which businesses are **actively running ads** on Meta (Facebook/Instagram) and Google (Search/YouTube/Display), with sample creatives.
- ⚡ **No browser** — pure HTTP, residential proxy by default, automatic IP rotation and retry; built to keep running against Google's defenses.

---

### Quick start

Just enter what you'd type in the Google Maps search box — **include the location**:

````

restaurants in New York

```
```

dentists in Miami, FL

```
```

coffee shops 90210

````

That's it. Everything else has a sensible default. Turn on the optional layers below only when you need them.

---

### Targeting (how to choose what to scrape)

You can target in four ways — use whichever fits:

| Input | Use it for |
|-------|-----------|
| `query` | A single search, e.g. `plumbers in Chicago`. The location is auto-detected. |
| `searchQueries` | A **batch** of searches in one run, e.g. `["dentists in Miami", "dentists in Orlando"]`. Results are de-duplicated across queries. |
| `startUrls` | Direct **Google Maps URLs** (place or search URLs). |
| `customGeolocation` | A **custom area** — either a point + radius `{ "lat": 25.77, "lng": -80.19, "radiusMeters": 1500 }` or a GeoJSON `Polygon` / `MultiPolygon` (coordinates in `[lng, lat]` order). |

If you provide an advanced targeting input you can leave `query` empty.

---

### Output

Each business is one dataset item. Base fields (always present when `Include Place Details` is on):

```json
{
  "name": "Joe's Pizza",
  "address": "7 Carmine St, New York, NY 10014",
  "phone": "+1 212-366-1182",
  "website": "https://www.joespizzanyc.com",
  "rating": 4.5,
  "reviews_count": 12847,
  "category": "Pizza restaurant",
  "categories": ["Pizza restaurant", "Italian restaurant"],
  "latitude": 40.7304,
  "longitude": -74.0022,
  "place_id": "ChIJr3k0v6VZwokRPCxBJnIcdTA",
  "google_maps_url": "https://www.google.com/maps/place/?q=place_id:ChIJr3k0v6VZwokRPCxBJnIcdTA",
  "hours": { "monday": "10 AM-2 AM", "tuesday": "10 AM-2 AM" },
  "price_level": "$10-20",
  "photos": ["https://lh3.googleusercontent.com/..."],
  "amenities": ["Outdoor seating", "Takeout", "Wheelchair accessible entrance"],
  "plus_code": "76QXQR66+RC"
}
````

Additional fields appear when the matching option is enabled: `reviews`, `permanently_closed`, `popular_times`, `found_via` (which target produced the row), the lead-enrichment columns (`email`, `emails`, `facebook` … `whatsapp`, `website_reachable`), the people columns (`business_lead`, `contacts`), and the ad-intelligence columns (`meta_ads_*`, `google_ads_*`). Anything not found is `null` — the base scrape is never affected.

***

### Input reference

#### Results & detail

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `maxResults` | integer | 100 | Max businesses to extract (0 = unlimited). |
| `language` | string | `en` | Two-letter result language (Google `hl`). |
| `zoom` | integer | 13 | Search granularity (1–21). Lower = wider area, higher = more detail. |
| `includeDetails` | boolean | true | Fetch full place details (hours, phone, website, price level, photos…). |

#### Complete place data

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `includePhotos` | boolean | true | Include up to 10 photo URLs per place. |
| `includePlaceExtras` | boolean | true | Include amenities, Plus Code and permanently-closed status. |
| `includePopularTimes` | boolean | false | Include the weekly popular-times histogram when available (experimental). |

#### Reviews

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `includeReviews` | boolean | false | Extract reviews for each business. |
| `reviewsLimit` | integer | 5 | Max reviews per business (up to 1000). |
| `minReviewRating` | integer | 0 | Keep only reviews rated ≥ this (1–5; 0 = off). |
| `reviewKeyword` | string | — | Keep only reviews whose text contains this keyword. |
| `reviewsSort` | select | newest | `newest` or `relevant`. |

Each review includes `author`, `rating`, `date`, `text`, `review_id`, `author_photo`, plus (when present) `owner_response_text`, `owner_response_date`, `reviewer_review_count`, `reviewer_is_local_guide`, `review_language` and `review_images`.

#### Lead enrichment (experimental add-on)

Visits each business's **own website** (plus contact/about/imprint pages) to extract contact data. Off by default; never changes the base scrape.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `includeEmails` | boolean | false | Find email addresses (deduplicated and MX-validated). |
| `includeSocials` | boolean | false | Find social profiles (Facebook, Instagram, LinkedIn, X/Twitter, YouTube, TikTok, WhatsApp). |
| `emailOnly` | boolean | false | Keep only businesses with an email (implies `includeEmails`). |
| `socialOnly` | boolean | false | Keep only businesses with a social profile (implies `includeSocials`). |
| `onlyWithWebsite` | boolean | false | Keep only businesses that have a real website. |
| `onlyWithoutWebsite` | boolean | false | Keep only businesses **without** a website (prospects for web/design agencies). |
| `maxPagesPerSite` | integer | 4 | Advanced: max pages crawled per website (1–10). |

#### People / contacts (experimental add-on)

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `includePersonnel` | boolean | false | Extract the people at each business (name, title, their own email/phone/LinkedIn). |
| `maxContactsPerBusiness` | integer | 10 | Max contacts per business (highest-confidence first). |
| `personnelMinConfidence` | select | low | Drop contacts below this tier (`low`/`medium`/`high`). |
| `onlyWithPersonnel` | boolean | false | Keep only businesses with at least one contact. |

Each business gains `business_lead` (org-level email/phone/socials) and `contacts[]` (people with `name`, `title`, `email`, `phone`, `linkedin`, `confidence`, `tier`, `source_urls`).

#### Ad intelligence (experimental add-on)

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `includeMetaAds` | boolean | false | Check the Meta Ad Library — is the business running Facebook/Instagram ads? With sample creatives. |
| `includeGoogleAds` | boolean | false | Check the Google Ads Transparency Center — is it running Search/YouTube/Display ads? |
| `onlyRunningAds` | boolean | false | Keep only businesses currently running ads. |
| `adCountry` | string | US | Two-letter country code for where the ads are shown (applies to both sources). |

#### Proxy

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `proxyConfiguration` | object | Apify Residential | Recommended — Google blocks datacenter IPs on Maps. Leave as-is. |
| `proxyUrl` | string | — | Advanced: a single custom HTTP proxy used instead of Apify Proxy. |

***

### Recipes

**Web-design leads (businesses with no website):**

```json
{ "query": "restaurants in Austin, TX", "onlyWithoutWebsite": true, "includePersonnel": true }
```

**Warm leads — businesses advertising right now, with their contacts:**

```json
{ "query": "dentists in Miami, FL", "includeMetaAds": true, "includeGoogleAds": true,
  "onlyRunningAds": true, "includeEmails": true, "includePersonnel": true }
```

**Reputation / review mining (5★ reviews mentioning a topic):**

```json
{ "query": "hotels in Paris", "includeReviews": true, "reviewsLimit": 50,
  "minReviewRating": 5, "reviewKeyword": "breakfast" }
```

**Whole-area sweep with a custom radius:**

```json
{ "query": "gyms", "customGeolocation": { "lat": 34.0522, "lng": -118.2437, "radiusMeters": 5000 } }
```

***

### Tips

- **Include a location** in your query (`plumbers in Chicago`); plain phrases like `plumbers Chicago` or `coffee 90210` also work.
- **Keep the residential proxy** — Google blocks datacenter IPs on Maps search.
- **Start with a small `maxResults`** to test, then scale up.
- The optional enrichment / ad-intelligence layers add run time and are **off by default** — they never change the base scrape.

### Limitations

- Results depend on what Google Maps returns for your query and location; some businesses have incomplete data.
- `popular_times` is experimental and not available for every place.
- The Google Ads Transparency Center does not expose the text of search ads (only creative previews/metadata).
- For ad lookups outside the US, set `adCountry` to the business's country (e.g. `GB`, `DE`) for accurate results.

# Actor input Schema

## `query` (type: `string`):

What to search for on Google Maps — exactly what you'd type in the search box. Works best as "<category> in <location>", e.g. "restaurants in New York" or "dentists in Miami". Plain phrases like "coffee shops Seattle" or "plumbers 90210" also work — the location is detected automatically. You can also leave this empty and use the Advanced targeting options below (batch queries, Google Maps URLs, or a custom area).

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

Run several searches in one go — one query per line. Each is run through the full pipeline and results are merged and de-duplicated by place. Example: \["dentists in Miami", "orthodontists in Miami", "dental clinics Fort Lauderdale"]. Leave empty to use the single Search Query above.

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

Scrape from Google Maps URLs (best-effort). A PLACE url (with a place feature id) fetches that single business. A SEARCH url (e.g. .../maps/search/...) re-runs that query. URLs that can't be parsed are skipped with a warning. Accepts plain URLs or {"url": "..."} objects.

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

Search an EXACT area without geocoding a place name. Provide either a point + radius: {"lat": 40.7128, "lng": -74.006, "radiusMeters": 3000}, or a GeoJSON geometry: {"type": "Polygon", "coordinates": \[\[\[lng,lat],...]]} (Polygon, MultiPolygon or Point supported). The search category comes from the Search Query field above. The area's bounding box is gridded directly.

## `maxResults` (type: `integer`):

Maximum number of businesses to extract. Set to 0 for unlimited (collect everything found).

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

Two-letter language code for result text, e.g. en, es, fr, de, it, pt, ja.

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

Google Maps zoom level (1-21). Lower values cover a larger area with less detail; higher values cover a smaller area with more detail. 13 is a good default for city-level searches.

## `includeDetails` (type: `boolean`):

Fetch detailed info for each business (hours, phone, website, amenities). Slower but more complete.

## `includePhotos` (type: `boolean`):

Add a 'photos' array of up to 10 business photo URLs (from the place-details response). Requires 'Include Place Details' to be on.

## `includePlaceExtras` (type: `boolean`):

Add 'amenities' (attribute strings), 'plus\_code' (Google Plus Code) and 'permanently\_closed' (boolean). Best-effort — fields are null when not present in Google's response. Requires 'Include Place Details'.

## `includePopularTimes` (type: `boolean`):

EXPERIMENTAL / rarely available. Attempts to extract the weekly 'popular\_times' busy histogram. Google's HTTP place endpoint almost never includes this data (it is normally loaded by a separate browser-only request), so in practice 'popular\_times' is null for virtually all places. Kept for forward-compatibility; do not rely on it. Off by default. Requires 'Include Place Details'.

## `includeReviews` (type: `boolean`):

Fetch reviews for each business. Increases run time and cost.

## `reviewsLimit` (type: `integer`):

Maximum number of reviews to fetch per business (only used when Include Reviews is enabled).

## `minReviewRating` (type: `integer`):

Keep only reviews rated at or above this many stars (1-5). Applied after fetching. 0 = keep all ratings (off). Reviews with no rating are always kept.

## `reviewKeyword` (type: `string`):

Keep only reviews whose text contains this phrase (case-insensitive substring). Applied after fetching. Leave empty to keep all reviews. Example: 'refund', 'rude', 'clean'.

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

Review ordering. Reviews are returned in Google's default order, which is 'Most relevant' first. Note: Google's HTTP review endpoint does not reliably expose a separate strict-newest ordering, so both options currently return the most-relevant order.

## `includeEmails` (type: `boolean`):

EXPERIMENTAL / BETA. Optional lead-enrichment add-on. Visits each business website (plus its contact / about / imprint pages) and extracts email addresses. Adds run time and is billed separately, per enriched lead. Off by default — the base scraper is unaffected.

## `includeSocials` (type: `boolean`):

EXPERIMENTAL / BETA. Optional lead-enrichment add-on. Extracts social profile links (Facebook, Instagram, LinkedIn, X/Twitter, YouTube, TikTok, WhatsApp) from each business website. Adds run time and is billed separately, per enriched lead. Off by default.

## `emailOnly` (type: `boolean`):

Filter: only output businesses for which at least one email address was found. Automatically enables email finding.

## `socialOnly` (type: `boolean`):

Filter: only output businesses for which at least one social profile was found. Automatically enables social profile finding.

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

Filter: only output businesses that have a real website (excludes those with only a social page, a directory listing, or no site at all).

## `onlyWithoutWebsite` (type: `boolean`):

Filter: only output businesses that do NOT have a real website — prime prospects for web-design and digital agencies.

## `maxPagesPerSite` (type: `integer`):

Advanced: max pages to crawl on each business website during lead/people enrichment (home + contact/about/team pages). Higher finds more contacts but is slower. Defaults to 4 (auto-raised to 6 when 'Find People / Contacts' is on).

## `includePersonnel` (type: `boolean`):

EXPERIMENTAL / BETA. Optional lead-enrichment add-on. Visits each business website and extracts the PEOPLE who work there — name, title, and their own email / phone / LinkedIn where published — as a 'contacts' list, plus a structured 'business\_lead'. Only the business's own site is used. Off by default.

## `maxContactsPerBusiness` (type: `integer`):

Maximum personnel contacts to output per business (highest-confidence first). Only used when 'Find People / Contacts' is enabled.

## `personnelMinConfidence` (type: `string`):

Drop personnel contacts below this confidence tier. 'low' keeps everything (recall-first); raise to 'medium' or 'high' for precision. Only used when 'Find People / Contacts' is enabled.

## `onlyWithPersonnel` (type: `boolean`):

Filter: only output businesses for which at least one personnel contact was found. Automatically enables 'Find People / Contacts'.

## `includeMetaAds` (type: `boolean`):

EXPERIMENTAL / BETA. Ad-intelligence add-on. Checks the public Meta Ad Library (https://www.facebook.com/ads/library) for each business and reports whether they are actively running ads on Facebook / Instagram — plus the active-ad count and a few sample creatives (call-to-action, landing page, ad copy). A strong buy signal for agencies. Matches conservatively on the business's Facebook page / website domain / name, so unrelated advertisers are not falsely attributed. Adds run time, uses residential proxy, billed separately per matched advertiser. Off by default.

## `includeGoogleAds` (type: `boolean`):

EXPERIMENTAL / BETA. Ad-intelligence add-on. Checks the public Google Ads Transparency Center (https://adstransparency.google.com) for each business website and reports whether they are actively running ads on Google — Search, YouTube and Display — plus the advertiser name, ad count, when ads were last shown, and sample creatives. Matched exactly on the business's own website domain, so attribution is precise. Adds run time, billed separately per matched advertiser. Off by default.

## `onlyRunningAds` (type: `boolean`):

Filter: only output businesses that are actively running ads. If neither 'Find Meta Ads' nor 'Find Google Ads' is selected, both are checked; otherwise only the selected source(s). Keeps any business currently advertising on an enabled platform.

## `adCountry` (type: `string`):

Two-letter ISO country code for the ad lookups (where the ads are shown), e.g. US, GB, DE. Applies to both the Meta Ad Library search and the Google Ads Transparency Center region. Defaults to US. Used when an ad-intelligence add-on is enabled.

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

Required for reliable results. Google blocks datacenter IPs on Maps search, so this defaults to Apify Residential proxy. Leave as-is unless you know what you're doing.

## `proxyUrl` (type: `string`):

Optional. A single HTTP proxy URL (http://user:pass@host:port) to use INSTEAD of Apify Proxy above. Leave empty to use the Proxy configuration.

## Actor input object example

```json
{
  "query": "restaurants in New York",
  "searchQueries": [],
  "startUrls": [],
  "customGeolocation": {},
  "maxResults": 100,
  "language": "en",
  "zoom": 13,
  "includeDetails": true,
  "includePhotos": true,
  "includePlaceExtras": true,
  "includePopularTimes": false,
  "includeReviews": false,
  "reviewsLimit": 5,
  "minReviewRating": 0,
  "reviewKeyword": "",
  "reviewsSort": "newest",
  "includeEmails": false,
  "includeSocials": false,
  "emailOnly": false,
  "socialOnly": false,
  "onlyWithWebsite": false,
  "onlyWithoutWebsite": false,
  "includePersonnel": false,
  "maxContactsPerBusiness": 10,
  "personnelMinConfidence": "low",
  "onlyWithPersonnel": false,
  "includeMetaAds": false,
  "includeGoogleAds": false,
  "onlyRunningAds": false,
  "adCountry": "US",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "query": "restaurants in New York",
    "searchQueries": [],
    "startUrls": [],
    "customGeolocation": {},
    "includePhotos": true,
    "includePlaceExtras": true,
    "includePopularTimes": false,
    "reviewsSort": "newest",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("buff_pineapple/google-maps-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 = {
    "query": "restaurants in New York",
    "searchQueries": [],
    "startUrls": [],
    "customGeolocation": {},
    "includePhotos": True,
    "includePlaceExtras": True,
    "includePopularTimes": False,
    "reviewsSort": "newest",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("buff_pineapple/google-maps-scraper").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 '{
  "query": "restaurants in New York",
  "searchQueries": [],
  "startUrls": [],
  "customGeolocation": {},
  "includePhotos": true,
  "includePlaceExtras": true,
  "includePopularTimes": false,
  "reviewsSort": "newest",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call buff_pineapple/google-maps-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Maps Scraper — Places, Leads & Contact Data",
        "description": "Scrape Google Maps places by search query. Returns name, full address, latitude/longitude, phone, website, rating, review count, category, price level, neighborhood, timezone, place ID and CID. HTTP-only — no browser, fast and cheap.",
        "version": "1.6",
        "x-build-id": "OvMuddvkBKgqedxVk"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/buff_pineapple~google-maps-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-buff_pineapple-google-maps-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/buff_pineapple~google-maps-scraper/runs": {
            "post": {
                "operationId": "runs-sync-buff_pineapple-google-maps-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/buff_pineapple~google-maps-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-buff_pineapple-google-maps-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "query": {
                        "title": "Search Query",
                        "type": "string",
                        "description": "What to search for on Google Maps — exactly what you'd type in the search box. Works best as \"<category> in <location>\", e.g. \"restaurants in New York\" or \"dentists in Miami\". Plain phrases like \"coffee shops Seattle\" or \"plumbers 90210\" also work — the location is detected automatically. You can also leave this empty and use the Advanced targeting options below (batch queries, Google Maps URLs, or a custom area)."
                    },
                    "searchQueries": {
                        "title": "Batch Search Queries (Precision Targeting)",
                        "type": "array",
                        "description": "Run several searches in one go — one query per line. Each is run through the full pipeline and results are merged and de-duplicated by place. Example: [\"dentists in Miami\", \"orthodontists in Miami\", \"dental clinics Fort Lauderdale\"]. Leave empty to use the single Search Query above.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "startUrls": {
                        "title": "Google Maps Start URLs",
                        "type": "array",
                        "description": "Scrape from Google Maps URLs (best-effort). A PLACE url (with a place feature id) fetches that single business. A SEARCH url (e.g. .../maps/search/...) re-runs that query. URLs that can't be parsed are skipped with a warning. Accepts plain URLs or {\"url\": \"...\"} objects.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "customGeolocation": {
                        "title": "Custom Geolocation (coordinates / radius / polygon)",
                        "type": "object",
                        "description": "Search an EXACT area without geocoding a place name. Provide either a point + radius: {\"lat\": 40.7128, \"lng\": -74.006, \"radiusMeters\": 3000}, or a GeoJSON geometry: {\"type\": \"Polygon\", \"coordinates\": [[[lng,lat],...]]} (Polygon, MultiPolygon or Point supported). The search category comes from the Search Query field above. The area's bounding box is gridded directly."
                    },
                    "maxResults": {
                        "title": "Max Results",
                        "minimum": 0,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Maximum number of businesses to extract. Set to 0 for unlimited (collect everything found).",
                        "default": 100
                    },
                    "language": {
                        "title": "Language",
                        "type": "string",
                        "description": "Two-letter language code for result text, e.g. en, es, fr, de, it, pt, ja.",
                        "default": "en"
                    },
                    "zoom": {
                        "title": "Zoom Level",
                        "minimum": 1,
                        "maximum": 21,
                        "type": "integer",
                        "description": "Google Maps zoom level (1-21). Lower values cover a larger area with less detail; higher values cover a smaller area with more detail. 13 is a good default for city-level searches.",
                        "default": 13
                    },
                    "includeDetails": {
                        "title": "Include Place Details",
                        "type": "boolean",
                        "description": "Fetch detailed info for each business (hours, phone, website, amenities). Slower but more complete.",
                        "default": true
                    },
                    "includePhotos": {
                        "title": "Include Photos",
                        "type": "boolean",
                        "description": "Add a 'photos' array of up to 10 business photo URLs (from the place-details response). Requires 'Include Place Details' to be on.",
                        "default": true
                    },
                    "includePlaceExtras": {
                        "title": "Include Amenities, Plus Code & Closed Status",
                        "type": "boolean",
                        "description": "Add 'amenities' (attribute strings), 'plus_code' (Google Plus Code) and 'permanently_closed' (boolean). Best-effort — fields are null when not present in Google's response. Requires 'Include Place Details'.",
                        "default": true
                    },
                    "includePopularTimes": {
                        "title": "Include Popular Times (experimental)",
                        "type": "boolean",
                        "description": "EXPERIMENTAL / rarely available. Attempts to extract the weekly 'popular_times' busy histogram. Google's HTTP place endpoint almost never includes this data (it is normally loaded by a separate browser-only request), so in practice 'popular_times' is null for virtually all places. Kept for forward-compatibility; do not rely on it. Off by default. Requires 'Include Place Details'.",
                        "default": false
                    },
                    "includeReviews": {
                        "title": "Include Reviews",
                        "type": "boolean",
                        "description": "Fetch reviews for each business. Increases run time and cost.",
                        "default": false
                    },
                    "reviewsLimit": {
                        "title": "Reviews per Business",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Maximum number of reviews to fetch per business (only used when Include Reviews is enabled).",
                        "default": 5
                    },
                    "minReviewRating": {
                        "title": "Minimum Review Rating",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Keep only reviews rated at or above this many stars (1-5). Applied after fetching. 0 = keep all ratings (off). Reviews with no rating are always kept.",
                        "default": 0
                    },
                    "reviewKeyword": {
                        "title": "Review Keyword Filter",
                        "type": "string",
                        "description": "Keep only reviews whose text contains this phrase (case-insensitive substring). Applied after fetching. Leave empty to keep all reviews. Example: 'refund', 'rude', 'clean'.",
                        "default": ""
                    },
                    "reviewsSort": {
                        "title": "Review Sort Order",
                        "enum": [
                            "newest",
                            "relevant"
                        ],
                        "type": "string",
                        "description": "Review ordering. Reviews are returned in Google's default order, which is 'Most relevant' first. Note: Google's HTTP review endpoint does not reliably expose a separate strict-newest ordering, so both options currently return the most-relevant order.",
                        "default": "newest"
                    },
                    "includeEmails": {
                        "title": "Find Email Addresses (experimental add-on)",
                        "type": "boolean",
                        "description": "EXPERIMENTAL / BETA. Optional lead-enrichment add-on. Visits each business website (plus its contact / about / imprint pages) and extracts email addresses. Adds run time and is billed separately, per enriched lead. Off by default — the base scraper is unaffected.",
                        "default": false
                    },
                    "includeSocials": {
                        "title": "Find Social Media Profiles (experimental add-on)",
                        "type": "boolean",
                        "description": "EXPERIMENTAL / BETA. Optional lead-enrichment add-on. Extracts social profile links (Facebook, Instagram, LinkedIn, X/Twitter, YouTube, TikTok, WhatsApp) from each business website. Adds run time and is billed separately, per enriched lead. Off by default.",
                        "default": false
                    },
                    "emailOnly": {
                        "title": "Only Keep Businesses With an Email",
                        "type": "boolean",
                        "description": "Filter: only output businesses for which at least one email address was found. Automatically enables email finding.",
                        "default": false
                    },
                    "socialOnly": {
                        "title": "Only Keep Businesses With a Social Profile",
                        "type": "boolean",
                        "description": "Filter: only output businesses for which at least one social profile was found. Automatically enables social profile finding.",
                        "default": false
                    },
                    "onlyWithWebsite": {
                        "title": "Only Keep Businesses With a Website",
                        "type": "boolean",
                        "description": "Filter: only output businesses that have a real website (excludes those with only a social page, a directory listing, or no site at all).",
                        "default": false
                    },
                    "onlyWithoutWebsite": {
                        "title": "Only Keep Businesses Without a Website",
                        "type": "boolean",
                        "description": "Filter: only output businesses that do NOT have a real website — prime prospects for web-design and digital agencies.",
                        "default": false
                    },
                    "maxPagesPerSite": {
                        "title": "Max Pages per Website (advanced)",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Advanced: max pages to crawl on each business website during lead/people enrichment (home + contact/about/team pages). Higher finds more contacts but is slower. Defaults to 4 (auto-raised to 6 when 'Find People / Contacts' is on)."
                    },
                    "includePersonnel": {
                        "title": "Find People / Contacts (experimental add-on)",
                        "type": "boolean",
                        "description": "EXPERIMENTAL / BETA. Optional lead-enrichment add-on. Visits each business website and extracts the PEOPLE who work there — name, title, and their own email / phone / LinkedIn where published — as a 'contacts' list, plus a structured 'business_lead'. Only the business's own site is used. Off by default.",
                        "default": false
                    },
                    "maxContactsPerBusiness": {
                        "title": "Max Contacts per Business",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum personnel contacts to output per business (highest-confidence first). Only used when 'Find People / Contacts' is enabled.",
                        "default": 10
                    },
                    "personnelMinConfidence": {
                        "title": "Minimum Contact Confidence",
                        "enum": [
                            "low",
                            "medium",
                            "high"
                        ],
                        "type": "string",
                        "description": "Drop personnel contacts below this confidence tier. 'low' keeps everything (recall-first); raise to 'medium' or 'high' for precision. Only used when 'Find People / Contacts' is enabled.",
                        "default": "low"
                    },
                    "onlyWithPersonnel": {
                        "title": "Only Keep Businesses With a Contact",
                        "type": "boolean",
                        "description": "Filter: only output businesses for which at least one personnel contact was found. Automatically enables 'Find People / Contacts'.",
                        "default": false
                    },
                    "includeMetaAds": {
                        "title": "Find Meta (Facebook / Instagram) Ads (experimental add-on)",
                        "type": "boolean",
                        "description": "EXPERIMENTAL / BETA. Ad-intelligence add-on. Checks the public Meta Ad Library (https://www.facebook.com/ads/library) for each business and reports whether they are actively running ads on Facebook / Instagram — plus the active-ad count and a few sample creatives (call-to-action, landing page, ad copy). A strong buy signal for agencies. Matches conservatively on the business's Facebook page / website domain / name, so unrelated advertisers are not falsely attributed. Adds run time, uses residential proxy, billed separately per matched advertiser. Off by default.",
                        "default": false
                    },
                    "includeGoogleAds": {
                        "title": "Find Google Ads (experimental add-on)",
                        "type": "boolean",
                        "description": "EXPERIMENTAL / BETA. Ad-intelligence add-on. Checks the public Google Ads Transparency Center (https://adstransparency.google.com) for each business website and reports whether they are actively running ads on Google — Search, YouTube and Display — plus the advertiser name, ad count, when ads were last shown, and sample creatives. Matched exactly on the business's own website domain, so attribution is precise. Adds run time, billed separately per matched advertiser. Off by default.",
                        "default": false
                    },
                    "onlyRunningAds": {
                        "title": "Only Keep Businesses Currently Running Ads",
                        "type": "boolean",
                        "description": "Filter: only output businesses that are actively running ads. If neither 'Find Meta Ads' nor 'Find Google Ads' is selected, both are checked; otherwise only the selected source(s). Keeps any business currently advertising on an enabled platform.",
                        "default": false
                    },
                    "adCountry": {
                        "title": "Ad Library Country",
                        "type": "string",
                        "description": "Two-letter ISO country code for the ad lookups (where the ads are shown), e.g. US, GB, DE. Applies to both the Meta Ad Library search and the Google Ads Transparency Center region. Defaults to US. Used when an ad-intelligence add-on is enabled.",
                        "default": "US"
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Required for reliable results. Google blocks datacenter IPs on Maps search, so this defaults to Apify Residential proxy. Leave as-is unless you know what you're doing.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    },
                    "proxyUrl": {
                        "title": "Custom proxy URL (advanced, optional)",
                        "type": "string",
                        "description": "Optional. A single HTTP proxy URL (http://user:pass@host:port) to use INSTEAD of Apify Proxy above. Leave empty to use the Proxy configuration."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
