# Google Maps Scraper - Leads, Emails & Reviews (`overbifrost/google-maps-business-data`) Actor

Find businesses on Google Maps by type and location. Get names, addresses, phone numbers, websites, ratings and review counts where available. Export to CSV, Excel or JSON, or use the API. Duplicate listings are removed, and incomplete or blocked searches are reported. No Google API key needed.

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

## Pricing

from $1.75 / 1,000 business records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## WIE — Maps Business Scraper

Discover businesses from Google Maps using a simple **Search + Location + Maximum businesses** workflow.

The Actor returns clean, versioned business records with source identity, query provenance, diagnostics and bounded run telemetry. The same reusable `@wie/maps` capability is also consumed in-process by WIE — Web Design Opportunity Finder; neither Actor invokes the other.

### Quick start

1. Enter **Search** — for example `plumber`.
2. Enter **Location** — for example `London, UK`.
3. Choose **Maximum businesses** — default 100, hard maximum 200.
4. Run.

The maximum is a hard cap, not a promise that Google will expose that many matching businesses. API inputs are strict: unknown properties are rejected instead of silently ignored.

Advanced settings let you select a locale, bounded browser concurrency and proxy strategy. Normal use requires no Maps URL, selectors, JSON, RPC knowledge or proxy credentials.

### Returned fields

Each Dataset row has `schemaVersion: 1` and may include:

- stable WIE `recordId` and observed Maps `sourceIdentity`;
- Google `placeId` when actually observable;
- business title, category, address, website and phone;
- Maps URL and coordinates when observable;
- rating/review count where directly available;
- sponsored and closed-status indicators where directly observable;
- query provenance, including result rank and requested/loaded/observed Maps URLs where available;
- ingestion time;
- explicit diagnostics.

Missing values are omitted. In particular, a missing `website` means only that the checked Maps source record did not establish a website. It is **not** proof that the business has no website elsewhere.

### Query outcomes

The run distinguishes:

- `COMPLETE` — bounded query completed;
- `ZERO_RESULTS` — query completed without a block/failure signal and no business result was observed;
- `PARTIAL` — some useful records were emitted but the query did not fully complete;
- `BLOCKED` — a challenge/CAPTCHA or equivalent block state was observed;
- `FAILED` — acquisition failed without a valid completed result.

A block or failure is never silently converted to zero results.

### Bounded acquisition behavior

The implementation uses Playwright to establish a real bounded Maps session. When that session exposes the structured Google Maps search-data endpoint used by the web application, WIE paginates that observed endpoint in 20-result steps and normalizes those source records directly. It does not require a customer Google API key and does not invent a Place ID when only another Maps identifier is present.

Rendered feed scrolling remains a bounded fallback for layouts where structured acquisition is unavailable or incomplete. A stagnant feed may be retried once in a fresh session; detail pages are then used only for feed-discovered place URLs. Sessions, concurrency, structured requests, scrolls, retries, result count and total query duration remain bounded by the same query deadline. A crashed detail page is replaced before the single retry, and a challenged detail session is not reused.

Images, media and fonts are blocked by default to reduce traffic. The scraper navigates only Google Maps URLs generated or observed by the Maps capability and does not crawl the extracted business websites. It does not solve CAPTCHAs or attempt unlimited retries.

### Proxy behavior and cost

Proxy choices:

- **Automatic (non-residential)** — default;
- **No proxy**;
- **Apify datacenter**;
- **Apify residential (metered)** — explicit opt-in only.

AUTO never silently selects residential traffic.

Run telemetry records browser activity, retries, blocks, emitted places and elapsed time. Cost fields distinguish confirmed, estimated and unknown values.

Store billing uses pay per event. One `business-scraped` event is charged for each validated unique business row after it has been persisted. The current Store price is **$0.004 per business** ($4.00 per 1,000 businesses), plus the standard Actor-start event. Platform usage is included in the event pricing rather than billed separately by this Actor. Duplicates, malformed rows and blocked/failed queries without emitted valid businesses are not charged the `business-scraped` event. The live Apify Store pricing configuration is authoritative if it changes after this README was published.

### What v1 does not do

This release intentionally excludes reviews, photos, email/contact enrichment, social profiles, website crawling, multiple search terms/locations per run, arbitrary Maps URL ingestion, outreach, monitoring, AI classification and CAPTCHA solving.

### International use

The contract preserves UTF-8 business names/addresses and does not impose Norway-specific address parsing. Deterministic fixtures cover US, UK, Norway, Sweden, Germany, France, Spain and Australia. Live international coverage is still being expanded, so customers should validate representative queries for their target market before large runs.

### Terms, privacy and downstream use

Automated collection of Google Maps content can carry contractual and data-use risk. Users should review the current Google/Maps terms, applicable law and their intended data-use model. This Actor does not provide legal advice.

Business listings can contain personal data, especially for sole traders. Customers are responsible for lawful downstream use and retention. WIE limits v1 to business-discovery fields and performs no sensitive-category inference or automated outreach.

### Release status

Published on the Apify Store. The release has passed repository CI and a live 50-result London acceptance run. Broader cost, proxy and international benchmarks remain ongoing operational work; partial, blocked and failed acquisition states remain explicit rather than being reported as successful zero-result runs.

# Actor input Schema

## `search` (type: `string`):

Business type or search term, for example plumber, dentist, accountant, or auto repair.

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

City, region, or area to search, for example London, UK; Austin, TX; or Sydney, Australia.

## `maxBusinesses` (type: `integer`):

Maximum unique business rows to return. Default 100; hard maximum 200.

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

Optional Maps locale such as en, en-GB, nb-NO, de-DE, or fr-FR.

## `concurrency` (type: `integer`):

Maximum simultaneous detail browser work. Default 2; hard maximum 4.

## `proxyStrategy` (type: `string`):

AUTO uses the normal configured Apify proxy route and never silently selects residential traffic. Residential is an explicit metered choice.

## Actor input object example

```json
{
  "maxBusinesses": 100,
  "language": "en",
  "concurrency": 2,
  "proxyStrategy": "AUTO"
}
```

# Actor output Schema

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

No description

## `runSummary` (type: `string`):

No description

## `chargeJournal` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("overbifrost/google-maps-business-data").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("overbifrost/google-maps-business-data").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 '{}' |
apify call overbifrost/google-maps-business-data --silent --output-dataset

```

## MCP server setup

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

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/IrwOg5sYrWJlQ8GcC/builds/Zc0xzIY1WykgmZ5TI/openapi.json
