# Google Maps Lead & Competitor Intelligence (`datahunter_labs/google-maps-lead-competitor-intelligence`) Actor

Discover local businesses from Google Maps and turn them into sales-ready leads with contact enrichment, opportunity scoring, reputation signals, competitor summaries, and change monitoring.

- **URL**: https://apify.com/datahunter\_labs/google-maps-lead-competitor-intelligence.md
- **Developed by:** [DataHunter Labs](https://apify.com/datahunter_labs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 business leads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

## Google Maps Lead & Competitor Intelligence

Turn Google Maps searches into sales-ready local-business intelligence instead of a raw place dump.

### What it returns

Each `business_lead` row can include:

- business name, category, address, phone, website, rating, review count, price level, coordinates, and Maps URL
- public emails, website phones, and public social-profile links when website enrichment is enabled
- `leadScore` and `leadTier`
- `contactabilityScore`
- `reputationRiskScore`
- `opportunitySignals` such as `no_website`, `reputation_improvement`, `review_generation`, and verified enrichment signals such as `weak_social_presence`
- `salesAngles` such as `website_build`, `reputation_management`, `review_growth`, `social_presence`, and `local_seo`
- monitoring fields for new/changed businesses when monitoring is enabled

Every search also returns a free `search_summary` with market coverage, rating, category, lead-tier, and sales-angle aggregates. `summaryScope` states whether the summary covers all returned rows or only returned changes.

### Why this Actor exists

Google Maps lead generation is one of the largest proven demand categories on Apify. Raw extraction is already highly competitive, so this Actor focuses on the next step: identifying which businesses are worth contacting and why.

Typical users:

- web-design and local-SEO agencies
- B2B lead-generation teams
- reputation-management agencies
- territory and market researchers
- sales teams looking for local businesses with identifiable digital gaps

### Input example

```json
{
  "searchQueries": ["dentists in Athens Greece"],
  "maxPlacesPerQuery": 25,
  "enrichWebsites": true,
  "monitorChanges": false
}
```

You can also supply Google Maps search/place URLs in `startUrls`. At least one query or Maps URL is required at runtime.

### Source and reliability

Google Maps is a dynamic browser source. This Actor uses Playwright because Google Maps is a dynamic browser-rendered source and static HTML parsing alone can be unreliable.

Network policy:

1. direct browser session first
2. detect blocking/challenge/timeout signals
3. bounded retry/backoff
4. only then use the configured proxy and rotate sessions up to `maxProxyRotations`
5. open a circuit after persistent blocking or a likely source-structure break instead of burning requests across every query
6. never attempt CAPTCHA solving
7. emit a diagnostic record rather than silently returning fake success

For production use, keep browser concurrency low and leave Apify Proxy available as fallback. Default memory is 4096 MB because browser-rendered Google Maps is resource intensive; concurrency is capped at 2.

### Website enrichment

When enabled, the Actor visits only the public business website plus a small number of likely contact/about pages. It extracts public, displayed contact information. It does not guess emails and does not log proxy credentials.

Website enrichment rejects localhost, private/reserved IP targets, credential-bearing URLs, and unsafe redirects before fetching them. When enrichment is disabled, email/social absence is treated as unknown rather than as a negative sales signal.

### Monitoring

`monitorChanges=true` creates a baseline scoped to the exact search/filter configuration. The first run does not label every result as falsely new. Later runs detect changes in rating, review count, address, phone, website, and closure status.

`onlyChanges=true` returns the full baseline on the first monitoring run and only new/changed leads afterward.

`missingBusinessesSinceLastRun` means a previously observed business is missing from the **current sampled search result set**. It does **not** claim that the business has permanently closed or disappeared from Google Maps.

### Pricing

This Actor uses Pay Per Event pricing:

- `lead-returned`: **$0.0035 per useful, deduplicated business lead**
- equivalent price: **$3.50 per 1,000 returned leads**
- Actor start: **$0.00005**

The `lead-returned` event is the primary billable event.

Search summaries, diagnostics, retries, proxy rotations, cache operations, and duplicate rows are not billed as lead events.

### Limits

- Google Maps can change its UI and anti-bot behavior.
- Browser scraping has higher platform cost than API/feed-based Actors.
- Website contact enrichment is best-effort and only reports public information actually found.
- A successful run is not considered valid if Google returns a CAPTCHA/challenge/hollow shell; the Actor reports a diagnostic instead.
- Google Maps result ranking can change between runs, so monitoring counts are scoped to the sampled result window configured by the user.

# Changelog

This Actor's version history is a separate document: https://apify.com/datahunter\_labs/google-maps-lead-competitor-intelligence/changelog.md

# Actor input Schema

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

Search phrases such as 'dentists in Berlin' or 'plumbers in Manchester'. Each query is processed independently.

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

Optional public Google Maps search or place URLs. Use these when you already have exact Maps URLs.

## `maxPlacesPerQuery` (type: `integer`):

Maximum number of unique business places returned for each search query or search URL.

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

BCP-47 style language code used for the Google Maps interface, for example en, de, fr, es, it, or el.

## `enrichWebsites` (type: `boolean`):

Visit each public business website and a small number of contact/about pages to extract displayed emails, phones, and social profiles.

## `maxWebsitePages` (type: `integer`):

Maximum number of public pages visited on each business website when website enrichment is enabled.

## `minimumRating` (type: `integer`):

Optional whole-star minimum rating filter from 0 to 5. Set to 0 to disable the filter.

## `minimumReviewCount` (type: `integer`):

Minimum Google Maps review count required for a returned business. Set to 0 to disable the filter.

## `requireWebsite` (type: `boolean`):

Return only businesses that expose a public website on Google Maps.

## `requirePhone` (type: `boolean`):

Return only businesses that expose a public phone number on Google Maps.

## `excludeClosed` (type: `boolean`):

Exclude businesses that Google Maps marks as permanently or temporarily closed.

## `monitorChanges` (type: `boolean`):

Persist business state across runs and detect new businesses or changes to rating, review count, phone, website, address, and closure status.

## `onlyChanges` (type: `boolean`):

When monitoring is enabled, return all businesses on the first baseline run and only new or changed businesses on later runs.

## `forceRefresh` (type: `boolean`):

Ignore cached query results and fetch fresh Google Maps data for this run.

## `cacheTtlMinutes` (type: `integer`):

How long successful query results may be reused before Google Maps is fetched again.

## `maxConcurrency` (type: `integer`):

Maximum number of Google Maps place pages processed concurrently. Use 1 for lowest blocking/memory risk; 2 can improve speed when enough memory is allocated.

## `pageTimeoutSeconds` (type: `integer`):

Maximum seconds allowed for a Google Maps page navigation before it is treated as a recoverable timeout.

## `maxRequestsPerRun` (type: `integer`):

Hard safety budget covering Google Maps navigations and optional website-enrichment HTTP requests.

## `maxRetries` (type: `integer`):

Maximum retry attempts after a timeout, transient source error, or detected blocking signal.

## `retryBackoffSeconds` (type: `integer`):

Base number of seconds used for bounded exponential retry backoff.

## `maxProxyRotations` (type: `integer`):

Maximum number of proxy-session rotations used only after a direct request is blocked or repeatedly fails.

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

Optional Apify or custom proxy configuration. Direct browsing is attempted first; configured proxies are used only after blocking or repeated transient failures.

## Actor input object example

```json
{
  "searchQueries": [
    "dentists in Athens Greece"
  ],
  "startUrls": [],
  "maxPlacesPerQuery": 3,
  "language": "en",
  "enrichWebsites": true,
  "maxWebsitePages": 1,
  "minimumRating": 0,
  "minimumReviewCount": 0,
  "requireWebsite": false,
  "requirePhone": false,
  "excludeClosed": true,
  "monitorChanges": false,
  "onlyChanges": false,
  "forceRefresh": true,
  "cacheTtlMinutes": 360,
  "maxConcurrency": 1,
  "pageTimeoutSeconds": 30,
  "maxRequestsPerRun": 12,
  "maxRetries": 1,
  "retryBackoffSeconds": 1,
  "maxProxyRotations": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Business leads, search summaries, and diagnostic rows.

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

Run status, result counts, request budget, proxy rotations, cache activity, monitoring state, and billing-limit state.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "dentists in Athens Greece"
    ],
    "startUrls": [],
    "maxPlacesPerQuery": 3,
    "language": "en",
    "enrichWebsites": false,
    "maxWebsitePages": 1,
    "minimumRating": 0,
    "minimumReviewCount": 0,
    "requireWebsite": false,
    "requirePhone": false,
    "excludeClosed": true,
    "monitorChanges": false,
    "onlyChanges": false,
    "forceRefresh": true,
    "cacheTtlMinutes": 0,
    "maxConcurrency": 1,
    "pageTimeoutSeconds": 30,
    "maxRequestsPerRun": 12,
    "maxRetries": 1,
    "retryBackoffSeconds": 1,
    "maxProxyRotations": 1,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datahunter_labs/google-maps-lead-competitor-intelligence").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["dentists in Athens Greece"],
    "startUrls": [],
    "maxPlacesPerQuery": 3,
    "language": "en",
    "enrichWebsites": False,
    "maxWebsitePages": 1,
    "minimumRating": 0,
    "minimumReviewCount": 0,
    "requireWebsite": False,
    "requirePhone": False,
    "excludeClosed": True,
    "monitorChanges": False,
    "onlyChanges": False,
    "forceRefresh": True,
    "cacheTtlMinutes": 0,
    "maxConcurrency": 1,
    "pageTimeoutSeconds": 30,
    "maxRequestsPerRun": 12,
    "maxRetries": 1,
    "retryBackoffSeconds": 1,
    "maxProxyRotations": 1,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("datahunter_labs/google-maps-lead-competitor-intelligence").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "dentists in Athens Greece"
  ],
  "startUrls": [],
  "maxPlacesPerQuery": 3,
  "language": "en",
  "enrichWebsites": false,
  "maxWebsitePages": 1,
  "minimumRating": 0,
  "minimumReviewCount": 0,
  "requireWebsite": false,
  "requirePhone": false,
  "excludeClosed": true,
  "monitorChanges": false,
  "onlyChanges": false,
  "forceRefresh": true,
  "cacheTtlMinutes": 0,
  "maxConcurrency": 1,
  "pageTimeoutSeconds": 30,
  "maxRequestsPerRun": 12,
  "maxRetries": 1,
  "retryBackoffSeconds": 1,
  "maxProxyRotations": 1,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call datahunter_labs/google-maps-lead-competitor-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datahunter_labs/google-maps-lead-competitor-intelligence"
        }
    }
}
```

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/0aYqKErsK2QMivOv6/builds/qMb7KYzZcC3VIzuMr/openapi.json
