# Google Maps Leads Scraper – Emails & AI Scoring (`computerdoit/google-maps-leads-scraper`) Actor

Turn Google Maps into qualified leads. Businesses with phone, website, hours and rating for $3.40 per 1,000. Add emails and socials from each business's own website (mail-server checked, billed only when found), full listing details and AI lead scoring. Export to CSV or CRM.

- **URL**: https://apify.com/computerdoit/google-maps-leads-scraper.md
- **Developed by:** [ComputerDoIt](https://apify.com/computerdoit) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.40 / 1,000 business listings

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

### 📍 What is Google Maps Leads Scraper?

**Google Maps Leads Scraper – Emails & AI Scoring** turns a Google Maps search into a lead list you can call, email and import into your CRM. Type a business type and a place, and get every listed business with its phone, website, address, hours and rating. Add the emails and social profiles from each business's own website, the full listing details, or an AI fit score against your ideal customer, with one click.

- **Build prospect lists:** every dentist, plumber or café in a city, with contacts ready for your outreach tool
- **Call the best leads first:** describe your ideal customer once and every business gets a 0–100 fit score with the reasons
- **Find the people:** owners and managers named on each business's own website, with their roles
- **Enrich the list you already have:** send names and websites from your CRM, with no Maps search and no per-row fee
- **Map a market:** count and compare businesses by area, category and rating

Built for agencies, sales teams and local-service marketers who need contactable leads, not just map pins.

##### What data can you get?

| | |
| --- | --- |
| 🏷️ Business name, category and description | 📍 Address, city, postal code and country |
| 🌍 Coordinates and plus code | ☎️ Phone number |
| 🌐 Website | ⭐ Rating and review count |
| 🕒 Opening hours and open / closed status | 🆔 Place ID, FID, CID and Maps link |
| 📧 Emails from the business's own website, with a mail-server check | 📱 Website phones, with the line type |
| 🔗 Facebook, Instagram, LinkedIn, X, YouTube, TikTok and Pinterest links | 🛎️ Amenities, accessibility, payments and other listing details |
| 🍽️ Menu and booking links, owner posts | 📸 Photo links and the cover photo |
| 🤖 AI profile, services and a 0–100 fit score with reasons | 👥 Owners and team named on the website, with roles |

> ⚠️ **Google shows Apify sessions a limited view of Maps.** It leaves out individual reviews, popular times, the rating breakdown and the price range, so those are never in the output. Nothing is guessed: a missing value stays empty.

### 💰 Pricing

You pay per result, with no start fee. Set a spending limit on each run and the Actor stays within it.

| What you get | Price |
| --- | --- |
| 🏢 Business row (always) | **$3.40 per 1,000** ($0.0034 each) |
| 📧 Website emails & socials | $0.002 per business website with contacts found |
| 🛎️ Full listing details | $0.001 per business with details found |
| 📸 Photo links | Free |
| 🤖 AI lead scoring | $0.008 per business scored |
| 👥 Owners & team (with AI lead scoring) | $0.004 per website where people are named |

Websites without contacts, listings without details and businesses the AI could not score cost nothing for that pack. Only valid, unique businesses delivered to your dataset are charged: duplicates, filtered-out businesses and candidates that never made it into the dataset are free. A partial run is charged for the businesses it delivered.

**Examples:** 1,000 businesses cost $3.40. A business with everything (contacts, details, AI score and people) costs $0.0034 + $0.002 + $0.001 + $0.008 + $0.004 = $0.0184.

### 🚀 Quick start

1. Enter a **Search query** (for example `dentist`) and a **Location** (for example `Leeds, United Kingdom`).
2. Set **Maximum business rows**.
3. Optionally pick packs under **Add data**.
4. Click **Start**, then open the **Leads** view or export the dataset.

The Console form starts with this small test, which reads at most five cafés in under a minute:

```json
{
  "search_query": "cafe",
  "location": "Lower Manhattan, New York, USA",
  "language": "en",
  "search_mode": "single",
  "detailProfile": "core",
  "detailTransport": "feed",
  "captureDetailEvidence": false,
  "max_results": 5,
  "geographicOptions": { "resultLimit": 10 },
  "maxSearchCells": 1,
  "maxSearchAttempts": 1,
  "maxNavigationAttempts": 12,
  "maxCandidateUrls": 10,
  "maxRunTimeSecs": 60,
  "maxConcurrentSearches": 1,
  "maxConcurrentExtractions": 1,
  "baseDelayMs": 500,
  "enableCache": false,
  "proxyConfiguration": { "useApifyProxy": false }
}
```

In one hosted run this test delivered all five businesses in 35 seconds without opening a business page. Results vary with the search and Google's view, so it is an example, not a guarantee. Through the API, settings you leave out use the defaults instead: 50 businesses and up to 600 seconds of scraping.

### ⬇️ Input

#### 🔍 Search query and location

`search_query` is what you would type into Google Maps, and `location` is where. The location steers the search but is not a strict boundary, so a few results can come from nearby. English (`en`) is the tested language.

#### ⚡ Fast by default

Businesses are read from Google's search results feed without opening each listing. In a 30-business test this took 61 seconds instead of 298 and used about a tenth of the compute. A business the feed cannot supply opens its listing as usual. The `category` is the one Google shows for your search; the other categories are in `subcategories`.

Set `detailProfile` to `full` to also read the email, social, booking, menu and service fields shown on the listing itself. This opens every listing in a browser and takes about ten times longer.

#### 📋 Several searches or direct listings

Use `targetJobs` instead of `search_query` and `location` to run several searches in one go (clear those two fields first). One `max_results` caps the whole run, and each search can have its own cap:

```json
{
  "targetJobs": [
    { "kind": "search", "search_query": "dentist", "location": "Leeds, United Kingdom", "max_results": 20 },
    { "kind": "search", "search_query": "orthodontist", "location": "Leeds, United Kingdom", "max_results": 20 }
  ],
  "max_results": 40
}
```

A job can also be a Google Maps listing URL (`"kind": "url"`), a Place ID (`"kind": "placeId"`) or a CID (`"kind": "cid"`), read with `"detailTransport": "browser"`. Short links (`maps.app.goo.gl`) and search URLs are rejected.

#### 🗺️ Strict area

For results strictly inside an area, give `search_bounds` (`south`, `west`, `north`, `east`) or `search_center` (`latitude`, `longitude`) with `radius_km`. Only businesses whose pin is inside the area are kept. Set `search_mode` to `geographic` to split a large area into smaller cells and reach more businesses.

#### 🎚️ Filters

- `min_rating` and `min_reviews` keep businesses at or above a rating or review count.
- `has_website` and `has_phone` keep businesses that list one.
- `has_email` keeps businesses whose Google listing shows an email. Google rarely shows an email on a listing, so `has_email: true` returns few businesses. For emails, add the **Website emails & socials** pack, which reads each business's own website.

`categories` and `exclude_chains` are kept for compatibility and are not applied. The experimental `mapsSelection` and `mapsExclusions` fields add finer filters and skip lists; their help text in the input form explains them.

#### ⏱️ Limits

`max_results` caps delivered businesses. `maxRunTimeSecs` caps scraping time (default 600). The other limits cap searches, page visits and candidates; reaching any of them returns what was found so far. The scraper time is separate from the Apify run timeout, so leave the platform timeout a few minutes longer. The default 2048 MB of memory suits feed runs; give `full` browser runs 4096 MB.

### ⬆️ Output

Open the **Leads** view for a CRM-ready table with one row per business: name, category, phone, website, best email, AI score, rating and address. **Overview** and **Details** show the remaining fields. Export as CSV, Excel or JSON, or read the dataset through the API.

#### Fields

| Group | Fields |
| --- | --- |
| Business | `name`, `description`, `category`, `subcategories` |
| Identity | `place_id`, `fid`, `cid`, `source_url` |
| Address | `address`, `street_address`, `city`, `state`, `country`, `postal_code`, `neighborhood` |
| Location | `latitude`, `longitude`, `plus_code` |
| Contact | `phone`, `phone_international`, `website` |
| Reviews | `rating`, `review_count` |
| Hours and status | `opening_hours`, `is_open`, `is_temporarily_closed`, `is_permanently_closed` |
| With `full`, when shown | `email`, `social_links`, `booking_url`, `menu_url`, `service_options` |
| Website emails & socials | `website_email`, `website_email_mail_server`, `website_phone`, `website_socials` |
| AI lead scoring | `ai_fit_score`, `ai_summary`, `ai_fit_reasons`, `ai_services`, `decision_makers` |
| Metadata | `scraped_at`, `data_quality_score` |

Packs also write linked datasets (`contacts`, `mapsSections`, `media`, `aiProfiles`, `people`), listed in the run's output tab. A field Google does not show is left out. `data_quality_score` is a rough completeness score, not an accuracy rating.

Here is an illustrative, synthetic partial shape of a row (not a real business):

```json
{
  "name": "Synthetic example cafe",
  "category": "Cafe",
  "address": "Unknown",
  "city": "Lower Manhattan, New York, USA",
  "opening_hours": {
    "Monday": [{ "open": "08:00", "close": "16:00" }]
  },
  "is_open": false
}
```

#### 📊 Run summary

The `SUMMARY` record in the run's key-value store explains each run: how many businesses were found and delivered, what each pack did, and why collection stopped. Its `outcome` is `completed`, `capped` (a limit was reached), `truncated` (the time limit was reached) or `empty`. Runs marked `limited_view` are partial by nature.

### 📧 Website emails & socials

Add the **Website emails & socials** pack (`websiteContacts`). The Actor visits each business's website, up to five pages (home, contact, about, team and locations), and collects:

- 📧 **Emails**, each with a mail-server (MX) check: `present`, `absent` or `unknown`. This catches dead domains, but no mailbox is contacted, so it is not a guarantee of delivery.
- ☎️ **Phones**, each with a line type (`mobile`, `fixed_line`, `toll_free` and so on) and region.
- 🔗 **Social profiles** and Google listing links.

The best email, a website phone that differs from the Maps phone and one link per social platform land on the business row. Every contact is in the linked `contacts` dataset with the page it came from. A website shared by several branches is read once, and its contacts are marked as company-wide.

Price: $0.002 per business website with contacts found. Websites without contacts are free.

### 🛎️ Full listing details

Add the **Full listing details** pack (`extendedMaps`) for the listing's about attributes (amenities, accessibility, payments), business links and owner posts in the `mapsSections` dataset, plus its photo links in `media`. Each section can be absent; nothing is guessed. Price: $0.001 per business with details found.

### 📸 Photo links

Add **Photo links** (`media`) for each listing's photo URLs, categories and cover photo in the `media` dataset, with no image downloads. Free. Full listing details already include them.

### 🤖 AI lead scoring

Add **AI lead scoring** (`aiProfiles`) together with **Website emails & socials**, since the AI reads the pages that pack fetches. Describe who you sell to in **Ideal customer**, for example *"Independent dental clinics with 2+ dentists that accept new patients"*.

For each business, an AI model reads its Maps facts and its own website, then writes:

- 🧾 a short profile, its services and the customers it serves
- 🎯 a 0–100 fit score against your ideal customer, with up to three reasons

Results are on the business row (`ai_fit_score`, `ai_summary`, `ai_fit_reasons`, `ai_services`) and in the `aiProfiles` dataset. Without an ideal customer you get profiles without scores. Price: $0.008 per business scored. A business the AI could not profile is delivered without AI fields and is not charged for AI.

#### 👥 Owners & team

With **Find owners & team** (on by default), the AI also lists the owners, managers and staff named on the business's own website. A person is kept only when their name and role both appear on that business's pages, so contacts are never invented. Each person row in the `people` dataset links to the page that names them. Price: $0.004 per website where people are named.

#### 🏅 Only deliver good matches

Set **Only deliver leads scoring at least** (`minFitScore`, 0–100) to keep only businesses that reach your bar. Businesses below it go to the `screened` dataset with their score and reasons, and are charged only the AI scoring fee ($0.008), not the business fee. The run does not search further when too few qualify, so set `max_results` above the number of leads you want.

### 📂 Enrich your own list

Already have businesses in a CRM or spreadsheet? Send them as `records` instead of a search (clear the search query and location first): up to 1,000 objects with `name` and `website`, plus optional `id`, `phone`, `address` and `category`.

```json
{
  "records": [
    { "id": "crm-17", "name": "Rose Bakery", "website": "https://rosebakery.example.com/" },
    { "name": "Oak Dental", "website": "oakdental.example.com", "phone": "+44 20 7946 0001" }
  ],
  "max_results": 2,
  "featurePacks": ["websiteContacts", "aiProfiles"],
  "idealCustomer": "Independent shops and clinics that take bookings"
}
```

Select **Website emails & socials**, and add **AI lead scoring** for fit scores and people. There is no business fee: you pay only for the contacts, scores and people found. Results go to the **Enriched records** dataset, and each record keeps your `id`. Set `max_results` to at least the size of your list.

### 🔌 Integrations

Export to CSV, Excel or JSON, or send results to Google Sheets, Make, Zapier or n8n with Apify integrations and webhooks. Call the Actor from your own code through the Apify API, or let an AI agent run it through Apify's MCP server. Schedule a task to refresh a lead list every week.

### ❓ FAQ

**How many results can I get?**
As many as Google Maps lists for your search, within `max_results` and the run limits. For more businesses in a big area, use a strict area with `search_mode: "geographic"`, or list several searches in `targetJobs`.

**Why are reviews and popular times missing?**
Google shows Apify sessions a limited view of Maps without individual reviews, popular times, the rating breakdown or the price range. A proxy does not change this.

**Are the emails verified?**
Each email's domain gets a mail-server (MX) check, which catches dead domains. No mailbox is contacted, so a passing check is not a guarantee of delivery.

**How accurate is AI lead scoring?**
The AI uses only the listing and the business's own website, and gives its reasons. Treat the score as a way to rank leads, not as a fact.

**Why did I get fewer businesses than I asked for?**
Filters, Google's view and the run limits can all stop a run early. The `SUMMARY` record says why. Try a broader search, fewer filters or a longer `maxRunTimeSecs`.

**Can I use a proxy?**
No. Proxies are turned off in this build, and a run with a proxy is rejected.

**Is it legal to scrape Google Maps?**
The Actor collects publicly visible business information. You are responsible for using it lawfully, including data-protection and anti-spam rules where you operate.

### 💬 Support

Open an issue in **Actor Issues** on this page with the run ID, your input and what you expected. Remove passwords, cookies and personal data first.

**Built by [ComputerDoIt](https://computerdoit.com).** Need these leads flowing into your CRM, outreach tool or an AI receptionist automatically? We build the automation around them.

### ⚖️ Responsible use

Google Maps Leads Scraper is not affiliated with Google, sponsored by Google or endorsed by Google. Google Maps is a Google service and trademark.

Use the Actor only for a lawful purpose. Respect privacy and data-protection rules: publicly visible contact details are not consent to unsolicited messages. The website pack reads public pages and does not consult robots.txt. Do not use the Actor to get around sign-in requirements, challenges or other access controls.

# Actor input Schema

## `search_query` (type: `string`):

Business type or search phrase to send to Google Maps, for example cafe or bicycle repair shop. Required for an ordinary search; omit both this and location when using targetJobs.

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

Required for an ordinary search, combined with search_query. Omit both when using targetJobs. It biases results but is not a strict boundary or an automatically geocoded area. With an explicit area, it is descriptive metadata and may be used as a fallback city value.

## `max_results` (type: `integer`):

Maximum accepted business rows, not a promised count. Console prefill: 5. API omission default: 50. Filters, Google restrictions and work budgets can stop collection earlier. This is a row cap, not an Apify currency spending limit.

## `featurePacks` (type: `array`):

Optional packs that run with the scrape. Website emails & socials: $0.002 per business or company website with contacts found. Full listing details: $0.001 per business with details found. Photo links: free (photo URLs and categories, no image downloads; included in Full listing details). AI lead scoring: $0.008 per business scored, plus $0.004 per website whose owners or team are named (needs Website emails & socials). Packs marked coming soon are previews only and are rejected outside preview mode. Selections never silently enable other paid dependencies. Duplicate selections are normalized in catalog order.

## `idealCustomer` (type: `string`):

Used by AI lead scoring: describe who you want to sell to, for example "Independent dental clinics with 2+ dentists that accept new patients". Each business gets a 0-100 fit score with reasons. Leave empty for AI profiles without scores.

## `findDecisionMakers` (type: `boolean`):

With AI lead scoring, list the owners, managers and staff the business's own website names, with their roles. $0.004 per website where people are found; nobody is invented.

## `minFitScore` (type: `integer`):

Optional, needs an Ideal customer brief. The run checks up to Max results businesses and delivers only those whose 0-100 fit score is at least this number. Businesses below it go to the Screened table with their score and reasons, charged $0.008 AI scoring each with no business fee. Businesses that could not be scored are not delivered and not charged. Not available with Your own list.

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

Google Maps interface language code. English (en) is the verified parser language. Other codes are passed to Maps, but field extraction may differ.

## `search_mode` (type: `string`):

An ordinary single search uses one root cell. Explicit targetJobs require single mode but may contain multiple ordered text searches, one cell each. Geographic requires explicit bounds or a center/radius and may subdivide cells based on a saturation heuristic; it cannot be combined with targetJobs. An explicit area applies pin-based containment. None guarantees complete coverage.

## `targetJobs` (type: `array`):

Alternative to top-level search_query and location: provide 1–1000 ordered search or direct jobs. A search entry needs its own query and location and may set a per-search accepted-row cap within max_results. Direct URL, Place ID and CID entries omit query/location; URL entries require a supported HTTPS Google Maps detail path. A direct URL with a Place ID plus a FID or CID is rejected even when syntactically compatible, until source-corroborated provenance is implemented. Shortlinks, search URLs and conflicting assertions are not resolved. All jobs share one browser pool, identity owner and global run/candidate/result budgets. An intentional per-search quota can advance to the next explicit job; source restrictions, stalls and global budget stops prevent later jobs. Each effective detail URL must retain the claimed FID, Place ID or CID, and decoded source identity must independently contain every asserted ID; a CID-only URL cannot confirm a FID. Any conflicting workload identity fails the run instead of publishing a silently retracted result. Direct browser work is blocked until outgoing redirect protection is proven. Direct jobs require explicit http-first transport and core profile, with browser fallback blocked on unavailable material. Search-only jobs retain browser support. Requires enableCache:false and single search mode without an explicit area. Place ID/CID locator formats and all source coverage require separate real-source proof; an offline test does not establish a successful listing or comprehensive results.

## `records` (type: `array`):

Enrich a list you already have instead of a Google Maps search: 1–1000 businesses, each with a name and website (plus optional id, phone, address and category). To use it, clear Search query and Location. Needs Website emails & socials; add AI lead scoring for fit scores and owners. Records go to their own Enriched records dataset and carry no $0.0034 business fee: you pay only the enrichment events they earn. Maximum business rows still caps how many records are enriched, so set it to at least your list size.

## `detailProfile` (type: `string`):

Default: core, read from the search feed; a run that asks for email (has_email or an email selection) uses full in the browser. Console starter: core. Both attempt IDs, business pins, names, categories, addresses, phones, website, aggregate rating/count, description, plus code, hours and status. Full additionally attempts email, social_links, booking_url, menu_url and service_options from supported Maps controls. Core excludes those five fields. Missing optional values are not verified absences. Neither profile performs external website enrichment or contact verification, or provides individual reviews, photos or popular times.

## `detailTransport` (type: `string`):

Default: search feed (core), or browser when the run asks for email or sets full. Search feed requires core: each business the search results feed already lists is read from that feed without opening its page, several times faster and cheaper, and any business the feed cannot supply opens its page as usual. Its category is the category Google shows for the search, which can differ from the business's primary category. Experimental http-first requires explicit core and uses the browser context's shared-cookie HTTP client for bounded structured details, with permitted browser fallback. Discovery still uses a browser. Available trial evidence showed fallback only, not a demonstrated HTTP-only benefit. Blocking or unsafe redirects stop the run. Its 4 MiB limit bounds parsing/retention, not Playwright download buffering.

## `search_bounds` (type: `object`):

Explicit rectangle. Supply this or search_center plus radius_km, never both. Unknown or outside business pins are excluded. Dateline-crossing and polar areas are unsupported. Leave unset for the text-location starter.

## `search_center` (type: `object`):

Circle center in decimal degrees. Requires radius_km. Do not also supply search_bounds. A text location does not supply this center automatically.

## `radius_km` (type: `number`):

Radius for an explicitly supplied search_center. A text location alone does not define a geographic boundary. Leave unset unless you supply a center.

## `geographicOptions` (type: `object`):

resultLimit controls URLs collected per cell in both modes. The starter sets it to 10. Other options control geographic subdivision. A collection quota below saturationThreshold marks truncation, not evidence of a Maps cap. Increasing these values does not guarantee more or complete results.

## `min_rating` (type: `number`):

Filter by the extracted aggregate Maps rating. Leave unset for the starter. This is not an independent quality or accuracy check.

## `min_reviews` (type: `integer`):

Filter by the extracted aggregate review count. Leave unset for the starter. Individual review text is not collected.

## `has_website` (type: `boolean`):

Keep only rows with an extracted website URL. Does not crawl or verify that website. False leaves this filter off.

## `has_phone` (type: `boolean`):

Keep only rows with an extracted phone number. Does not verify ownership, reachability or carrier. False leaves this filter off.

## `has_email` (type: `boolean`):

Google rarely shows an email on a listing, so this filter returns few businesses. For emails, add the Website emails & socials pack, which reads each business's own website. Full can collect email from supported dedicated Maps controls, without external website enrichment or email verification. Core does not attempt email and rejects an active has_email filter before launch. False leaves this filter off.

## `maxRunTimeSecs` (type: `integer`):

Absolute scraper work budget, followed by bounded cleanup. Console starter: 60 seconds. API omission default: 600 seconds. This is not the Apify platform timeout or a billing cap. Leave separate platform time for startup, cleanup and publication. Deadline-limited output is marked truncated.

## `maxSearchCells` (type: `integer`):

Maximum logical search cells across the invocation, including each explicit targetJobs text search and an ordinary root. Direct targets do not consume a search cell. Starter: 1. Hitting this budget marks incomplete exploration, not complete geographic coverage.

## `maxSearchAttempts` (type: `integer`):

Maximum search-page navigation attempts, including retries. Starter: 1.

## `maxNavigationAttempts` (type: `integer`):

Shared cap across searches, HTTP detail dispatches and manually followed redirects, browser detail navigations, consent submissions and retries. Starter: 12. This does not count page subresource requests.

## `maxCandidateUrls` (type: `integer`):

Maximum distinct candidates admitted for details before final qualification. Starter: 10. Known outside-area pins do not consume this budget. A candidate is not a delivered business row.

## `maxConcurrentSearches` (type: `integer`):

Maximum concurrent searches. Starter and API default: 1. Global run and navigation budgets still apply.

## `maxConcurrentExtractions` (type: `integer`):

Maximum simultaneous business-detail extractions. Console starter: 1. API omission default: 3.

## `baseDelayMs` (type: `integer`):

Base pacing delay between actions. Starter and API default: 500 ms. Keep direct runs small and stop on blocking rather than retrying for a larger count.

## `enableCache` (type: `boolean`):

Reuse option-aware local cached results. Leave off for a fresh run. Explicit-area searches do not reuse cached coverage. targetJobs, evidence capture, active Maps selection and exclusions require this setting off.

## `categories` (type: `array`):

Compatibility input only. Category filtering is not currently applied by this Actor. Leave unset and use the search query to express the business type.

## `exclude_chains` (type: `boolean`):

Compatibility input only. Chain exclusion is not currently applied by this Actor, even when true.

## `skipWebsiteEnrichment` (type: `boolean`):

Compatibility setting. This Actor does not perform external website email/social enrichment, even when false.

## `skipReviewsDistribution` (type: `boolean`):

Compatibility setting. Per-star review breakdown is not implemented, even when false. Both profiles retain aggregate rating and review count.

## `skipAttributes` (type: `boolean`):

Compatibility setting. General amenities/accessibility attributes are not implemented, even when false. Full still attempts dedicated Maps service_options controls. Core does not.

## `mapsSelection` (type: `object`):

Optional AND-combined current-detail criteria, with OR within each exact category list. Requires enableCache:false. Zero and false are active. Contact scope defaults to maps-observation, not universal business absence. All contact absence is blocked until explicit source proof exists. Website-observation and core email are also blocked. previewFeatures:true reports these blockers without scraping. Empty objects/lists and any predicates are no-ops. Do not overlap legacy numeric filters or active compatibility flags. Maximum 8192 normalized UTF-8 JSON bytes; each raw category list is limited to 4096 JSON bytes before deduplication. No new price, advanced pack or source coverage is enabled.

## `mapsExclusions` (type: `object`):

Optional exclusion keys. Requires enableCache:false. Omitted/empty controls are no-ops. At most 1000 raw entries combined and 262144 UTF-8 JSON bytes before deduplication. Place IDs remain case-sensitive; CIDs must be strings, including zero. Supplied keys are not business bridges. Identity reconciliation runs before selection and may retract earlier rows without refunding work. Contact matching and person scope are blocked, not silently ignored. Short and search URLs are rejected; no resolver is run. Prior business datasets require complete bounded reads owned by the same current run user, at most 4 datasets/1000 rows/33 requests within one 30,000 ms deadline captured before enqueue. Metadata checks are not a transaction. Targets are prepared lazily after identity ingestion; one shared logical source buffer retains actual readers through cleanup. These are not heap/RSS guarantees. Preview reports counts and gates without reading datasets. No new price, provider activation or source-coverage claim.

## `previewFeatures` (type: `boolean`):

Inspect effective Maps settings and planned feature gates without scraping, website/model requests, dataset publication or charge calls. Writes only FEATURE_PREVIEW and preserves existing SUMMARY/publication evidence. Base-price estimates are not verified billing quotes. A normal Actor invocation can still consume platform resources.

## `captureDetailEvidence` (type: `boolean`):

Diagnostic opt-in for the first granted detail work item, never a replacement target. Requires result caching off. Captures only permitted field observations already consumed by extraction, not full HTML or session data. Stores at most one compact JSON artifact under DETAIL_EVIDENCE, up to 2 MiB. Missing, private, oversized or failed capture is not successful proof. No extra navigation, website enrichment or accuracy certification.

## `captureWorkCheckpoint` (type: `boolean`):

Diagnostic opt-in to capture actual sealed Maps records and native work/resource/cost state before business publication. Omitted or false adds no checkpoint I/O. Reserves exactly 30,000 ms (30 seconds) upfront before source work inside the existing configured/platform envelope, without increasing maxRunTimeSecs or renewing deadlines. Requires maxRunTimeSecs > 30 and enough platform reserve for capture, the existing cleanup allowance, up to 90 seconds for publication/SUMMARY and 5 seconds for exit. Hosted captures use WORK_CHECKPOINT_V1 and WC1\_<sha256> KVS chunks. LOCAL captures use a persistent MemoryStorage sidecar, not Actor.getValue. Checksums establish integrity only: no automatic resume, authenticity, ownership, antirollback or trusted supplier-cost restoration. Existing manifests are refused before new source work, not adopted or overwritten. Any prior publication intent stays reconcile-only. Captured work is not proof of delivered or billed output. Feature previews never capture work.

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

This build makes direct requests. Keep useApifyProxy false. Enabled proxy settings and nonempty or malformed proxyUrls are rejected before launch, not silently ignored.

## Actor input object example

```json
{
  "search_query": "cafe",
  "location": "Lower Manhattan, New York, USA",
  "max_results": 5,
  "featurePacks": [],
  "findDecisionMakers": true,
  "language": "en",
  "search_mode": "single",
  "detailProfile": "core",
  "detailTransport": "feed",
  "geographicOptions": {
    "resultLimit": 10
  },
  "has_website": false,
  "has_phone": false,
  "has_email": false,
  "maxRunTimeSecs": 60,
  "maxSearchCells": 1,
  "maxSearchAttempts": 1,
  "maxNavigationAttempts": 12,
  "maxCandidateUrls": 10,
  "maxConcurrentSearches": 1,
  "maxConcurrentExtractions": 1,
  "baseDelayMs": 500,
  "enableCache": false,
  "exclude_chains": false,
  "skipWebsiteEnrichment": true,
  "skipReviewsDistribution": true,
  "skipAttributes": true,
  "previewFeatures": false,
  "captureDetailEvidence": false,
  "captureWorkCheckpoint": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

## `datasets` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `featurePreview` (type: `string`):

No description

## `workCheckpoint` (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 = {
    "search_query": "cafe",
    "location": "Lower Manhattan, New York, USA",
    "max_results": 5,
    "language": "en",
    "search_mode": "single",
    "detailProfile": "core",
    "detailTransport": "feed",
    "geographicOptions": {
        "resultLimit": 10
    },
    "maxRunTimeSecs": 60,
    "maxSearchCells": 1,
    "maxSearchAttempts": 1,
    "maxNavigationAttempts": 12,
    "maxCandidateUrls": 10,
    "maxConcurrentSearches": 1,
    "maxConcurrentExtractions": 1,
    "baseDelayMs": 500,
    "enableCache": false,
    "captureDetailEvidence": false,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("computerdoit/google-maps-leads-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 = {
    "search_query": "cafe",
    "location": "Lower Manhattan, New York, USA",
    "max_results": 5,
    "language": "en",
    "search_mode": "single",
    "detailProfile": "core",
    "detailTransport": "feed",
    "geographicOptions": { "resultLimit": 10 },
    "maxRunTimeSecs": 60,
    "maxSearchCells": 1,
    "maxSearchAttempts": 1,
    "maxNavigationAttempts": 12,
    "maxCandidateUrls": 10,
    "maxConcurrentSearches": 1,
    "maxConcurrentExtractions": 1,
    "baseDelayMs": 500,
    "enableCache": False,
    "captureDetailEvidence": False,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("computerdoit/google-maps-leads-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 '{
  "search_query": "cafe",
  "location": "Lower Manhattan, New York, USA",
  "max_results": 5,
  "language": "en",
  "search_mode": "single",
  "detailProfile": "core",
  "detailTransport": "feed",
  "geographicOptions": {
    "resultLimit": 10
  },
  "maxRunTimeSecs": 60,
  "maxSearchCells": 1,
  "maxSearchAttempts": 1,
  "maxNavigationAttempts": 12,
  "maxCandidateUrls": 10,
  "maxConcurrentSearches": 1,
  "maxConcurrentExtractions": 1,
  "baseDelayMs": 500,
  "enableCache": false,
  "captureDetailEvidence": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call computerdoit/google-maps-leads-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,computerdoit/google-maps-leads-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/9ZL5E3fTkksnCKh6f/builds/XNcDAfaCKgQlQ4UJz/openapi.json
