# Google Maps Business Scraper (`technicaldost/google-maps-business-scraper`) Actor

Extract business listings with reviews, hours, photos, ratings, and geo as structured JSON from public business pages (LocalBusiness schema.org) and the official Google Places API.

- **URL**: https://apify.com/technicaldost/google-maps-business-scraper.md
- **Developed by:** [Technical Dost Solutions](https://apify.com/technicaldost) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 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/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 Business Scraper

### What this Actor does

Extract local business listings (name, contact, hours, rating, reviews, photos, and geo coordinates) as clean, structured JSON.

The Actor runs in two compliant modes:

- **Structured-data mode**: processes user-supplied public business listing or place pages and parses schema.org `LocalBusiness` JSON-LD (including `Restaurant`, `Store`, and `Organization`).
- **Places API mode**: when you supply a Google Places API key and search terms, the Actor uses the official Google Places Text Search API, the compliant way to get live Google Maps data.

It normalizes useful fields, deduplicates rows by business name and address, and saves structured records to the Apify dataset.

### Why this Actor is useful

Teams pay for this kind of extraction because it saves manual research, builds repeatable lead lists, enriches CRMs, and turns public business data into clean, API-ready datasets, without violating Google's Terms of Service.

### Who this is for

- Lead generation agencies
- Local SEO consultants
- B2B sales teams
- Market researchers
- Directory and aggregator builders
- Small business marketers
- Data enrichment teams

### Common use cases

- Build local business lead lists for sales outreach
- Enrich CRM records with contact and geo data
- Monitor ratings and review counts for target businesses
- Populate local directories and aggregators
- Run local market research by category and area

### Input

You must provide **either** `startUrls` **or** both `placesApiKey` and `searchTerms`. If neither is supplied, the Actor stops early with a clear error.

- `startUrls`: Public business listing or place pages to extract from. Use only pages you are allowed to access without login or bypassing access controls. Do not point this at `google.com/maps`.
- `searchTerms`: Search queries used only in Places API mode (for example `coffee shops in Austin TX`).
- `placesApiKey`: Optional Google Places API key (stored as a secret). Enables the official Places API mode.
- `maxItems`: Maximum number of rows to save.
- `maxConcurrency`: Number of pages processed in parallel. The default is intentionally conservative.
- `includeReviews`: Include public reviews (author, body, rating) when available.
- `requestTimeoutSecs`: Maximum time to spend on a single page or API request.
- `proxyConfiguration`: Optional Apify proxy configuration where permitted by your source review.

### Output

- `businessName`: Business or organization name.
- `category`: Business category or schema.org type.
- `address`: Street, locality, region, and country as published.
- `latitude` / `longitude`: Geo coordinates when available.
- `phone`: Public phone number.
- `website`: Public website URL.
- `rating`: Aggregate rating value.
- `reviewCount`: Number of ratings or reviews.
- `priceLevel`: Price range indicator.
- `hours`: Opening hours lines when available.
- `photos`: Photo URLs or references.
- `reviews`: Public reviews (author, reviewBody, ratingValue) when `includeReviews` is enabled.
- `placeUrl`: Canonical place or map URL.
- `sourceUrl`: URL where the data was extracted.
- `detectedAt`: Timestamp when this Actor extracted the row.
- `extractionMethod`: `structured_data` for JSON-LD listings, or `places_api` for the Google Places API.
- `confidenceScore`: Heuristic confidence based on data source and completeness.
- `missingFields`: Output fields that were not available from the source.

### Sample input

```json
{
  "startUrls": [
    {
      "url": "https://example.com/restaurants/blue-harbor-cafe"
    }
  ],
  "maxItems": 50,
  "maxConcurrency": 3,
  "includeReviews": true,
  "requestTimeoutSecs": 30
}
````

### Sample output

```json
{
  "businessName": "Blue Harbor Cafe",
  "category": "Restaurant",
  "address": "120 Harbor St, Austin, TX, US",
  "latitude": 30.2672,
  "longitude": -97.7431,
  "phone": "+1-512-555-0142",
  "website": "https://blueharborcafe.example.com",
  "rating": 4.6,
  "reviewCount": 318,
  "priceLevel": "$$",
  "hours": [
    "Monday, Tuesday, Wednesday, Thursday 08:00-21:00",
    "Friday, Saturday 08:00-23:00"
  ],
  "photos": [
    "https://example.com/photos/blue-harbor-1.jpg"
  ],
  "reviews": [
    {
      "author": "Jordan M.",
      "reviewBody": "Great coffee and harbor views. Friendly staff.",
      "ratingValue": 5
    }
  ],
  "placeUrl": "https://blueharborcafe.example.com",
  "sourceUrl": "https://example.com/restaurants/blue-harbor-cafe",
  "detectedAt": "2026-06-27T00:00:00.000Z",
  "extractionMethod": "structured_data",
  "confidenceScore": 0.9,
  "missingFields": []
}
```

### How to use

Run this Actor on Apify with public listing URLs, or with a Google Places API key plus search terms. Export the dataset as JSON, CSV, Excel, or through the Apify API, then connect the output to Google Sheets, Make, Zapier, a webhook, your CRM, or an internal dashboard. For monitoring, save the input as an Apify task and schedule recurring runs.

### Pricing

This Actor is designed for pay-per-event pricing at **$0.005 per listing** saved to the dataset. You pay only for the business rows you extract.

### Best practices

- Provide reviewed public listing URLs, or use Places API mode for live Google Maps data.
- Prefer pages with schema.org `LocalBusiness` JSON-LD for the highest-quality structured output.
- Keep `maxConcurrency` low for smaller websites.
- Use specific `searchTerms` (category plus location) in Places API mode to keep results relevant.
- Review source website rules and Google Places API terms before scheduling recurring runs.

### Compliance and responsible use

This Actor does **not** scrape `google.com/maps` directly, which violates Google's Terms of Service. Instead it relies on two compliant sources: public schema.org `LocalBusiness` JSON-LD published on pages you are allowed to access, and the official Google Places API (which requires your own API key and is billed by Google).

It is for public data only. It must not be used to bypass logins, paywalls, CAPTCHAs, or security systems, collect private or sensitive personal data, or support spam or abuse. You are responsible for following applicable laws, Google's API terms, and source website rules.

### Limitations

- Output quality depends on the public structured data available on the source pages.
- Places API mode requires your own Google Places API key and is subject to Google's quotas and billing.
- Some fields may be empty when the source does not publish them; missing values are reported in `missingFields`, never invented.
- The Actor does not claim support for any specific third-party platform beyond the official Places API.
- Website markup and access policies can change.

### Troubleshooting

- Empty output in structured-data mode usually means the page has no public `LocalBusiness` JSON-LD.
- A "No usable input" error means you provided neither `startUrls` nor both `placesApiKey` and `searchTerms`.
- Places API errors usually indicate an invalid key, disabled API, or exceeded quota.
- Slow runs can usually be improved by lowering `maxConcurrency`.

### Changelog

- v0.1.0: Initial release with structured-data and Google Places API modes.

# Actor input Schema

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

Public business listing or place pages to extract from. The Actor parses LocalBusiness schema.org JSON-LD on these pages. Use only URLs you are allowed to access without login, paywall bypass, CAPTCHA bypass, or security circumvention. Do not point this at google.com/maps, which is prohibited by Google's Terms of Service.

## `searchTerms` (type: `array`):

Optional search queries used only when a Google Places API key is supplied. Each term runs a Places Text Search (for example 'coffee shops in Austin TX').

## `placesApiKey` (type: `string`):

Optional Google Places API key. When provided together with searchTerms, the Actor uses the official Google Places API (the compliant way to get live Google Maps data) instead of scraping google.com/maps.

## `maxItems` (type: `integer`):

Maximum number of normalized business rows to save. The Actor stops pushing new rows when this limit is reached.

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

How many pages to process at once. Lower this for small websites or cautious monitoring.

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

Include public reviews (author, body, rating) when they are available in structured data or the Places API response.

## `requestTimeoutSecs` (type: `integer`):

Maximum time to spend processing a single page before it is treated as failed.

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

Optional Apify proxy configuration. Use only where permitted by the source website and your compliance process.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://example.com/"
    }
  ],
  "maxItems": 50,
  "maxConcurrency": 3,
  "includeReviews": true,
  "requestTimeoutSecs": 30
}
```

# 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 = {
    "startUrls": [
        {
            "url": "https://example.com/"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("technicaldost/google-maps-business-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 = { "startUrls": [{ "url": "https://example.com/" }] }

# Run the Actor and wait for it to finish
run = client.actor("technicaldost/google-maps-business-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 '{
  "startUrls": [
    {
      "url": "https://example.com/"
    }
  ]
}' |
apify call technicaldost/google-maps-business-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Maps Business Scraper",
        "description": "Extract business listings with reviews, hours, photos, ratings, and geo as structured JSON from public business pages (LocalBusiness schema.org) and the official Google Places API.",
        "version": "0.1",
        "x-build-id": "S6D5WDuL6MMJLIcin"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/technicaldost~google-maps-business-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-technicaldost-google-maps-business-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/technicaldost~google-maps-business-scraper/runs": {
            "post": {
                "operationId": "runs-sync-technicaldost-google-maps-business-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/technicaldost~google-maps-business-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-technicaldost-google-maps-business-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": {
                    "startUrls": {
                        "title": "Public business listing URLs",
                        "type": "array",
                        "description": "Public business listing or place pages to extract from. The Actor parses LocalBusiness schema.org JSON-LD on these pages. Use only URLs you are allowed to access without login, paywall bypass, CAPTCHA bypass, or security circumvention. Do not point this at google.com/maps, which is prohibited by Google's Terms of Service.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "searchTerms": {
                        "title": "Search terms (Places API mode)",
                        "type": "array",
                        "description": "Optional search queries used only when a Google Places API key is supplied. Each term runs a Places Text Search (for example 'coffee shops in Austin TX').",
                        "items": {
                            "type": "string"
                        }
                    },
                    "placesApiKey": {
                        "title": "Google Places API key",
                        "type": "string",
                        "description": "Optional Google Places API key. When provided together with searchTerms, the Actor uses the official Google Places API (the compliant way to get live Google Maps data) instead of scraping google.com/maps."
                    },
                    "maxItems": {
                        "title": "Maximum results",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum number of normalized business rows to save. The Actor stops pushing new rows when this limit is reached.",
                        "default": 50
                    },
                    "maxConcurrency": {
                        "title": "Maximum concurrency",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "How many pages to process at once. Lower this for small websites or cautious monitoring.",
                        "default": 3
                    },
                    "includeReviews": {
                        "title": "Include reviews",
                        "type": "boolean",
                        "description": "Include public reviews (author, body, rating) when they are available in structured data or the Places API response.",
                        "default": true
                    },
                    "requestTimeoutSecs": {
                        "title": "Request timeout seconds",
                        "minimum": 5,
                        "maximum": 180,
                        "type": "integer",
                        "description": "Maximum time to spend processing a single page before it is treated as failed.",
                        "default": 30
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Optional Apify proxy configuration. Use only where permitted by the source website and your compliance process."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
