---
title: "Google Maps scraper"
description: "Scrape Google Maps places as JSON: names, categories, ratings, review counts, addresses, phones, websites, hours and reviews. One API request from Python or MCP."
canonical: https://www.zenrows.com/scrape/google-maps
updated: 2026-10-20
---

# Google Maps scraper

The Zenrows Google Maps scraper turns a Maps search or place URL into JSON: place names, categories, star ratings and review counts for every listing, plus the address, phone, website, plus code, weekly opening hours, rating distribution and top reviews of a single place. Fetch in Adaptive Stealth Mode opens the page and Extract returns the fields. Run it from an API call, the CLI or an AI agent.

- Site: google.com/maps
- Returns: Places, ratings, addresses, phones, websites, opening hours and reviews

## Run it: one Google Maps search in, JSON out

```json Input
{
  "url": "https://www.google.com/maps/search/coffee+shops+in+austin+tx",
  "mode": "auto",
  "extract": "auto",
  "proxy_country": "us"
}
```

```json Output
{
  "search_query": null,
  "place_results": [
    {
      "name": "Epoch Coffee",
      "cuisine": "Coffee shop",
      "rating": 4.5,
      "review_count": "2,538",
      "price_range": null,
      "place_id": null
    },
    {
      "name": "Mozart's Coffee Roasters",
      "cuisine": "Coffee shop",
      "rating": 4.5,
      "review_count": "10,982",
      "price_range": null,
      "place_id": null
    },
    {
      "name": "Terrible Love",
      "cuisine": "Coffee shop",
      "rating": 4.9,
      "review_count": "432",
      "price_range": null,
      "place_id": null
    }
  ]
}
```

Request and output of a live call to a Google Maps search on Oct 20, 2026, trimmed to three of the places returned. A field is returned when the listing shows it.

## What data can you scrape from Google Maps?

Google Maps has two page types that matter for data. A search (`/maps/search/…`) returns a list of places with their headline numbers. A place page returns one business in full: contact details, hours, the star distribution and reviews. Extract reads both, and these are the fields teams use most.

| Field | What it holds | Example |
|---|---|---|
| `place_results[].name` | Business name as listed on Maps (search) | `Epoch Coffee` |
| `place_results[].cuisine` | The category Google shows under the name (search) | `Coffee shop` |
| `place_results[].rating` | Average star rating out of 5 (search) | `4.5` |
| `place_results[].review_count` | Number of reviews, as printed (search) | `10,982` |
| `place_results[].price_range` | Price level, when the listing shows one (search) | `null` |
| `place.name` | Business name on the place page | `Franklin Barbecue` |
| `place.category` | Primary business category | `Barbecue restaurant` |
| `place.address` | Full street address | `900 E 11th St, Austin, TX 78702` |
| `place.phone` | Phone number as displayed | `(512) 653-1187` |
| `place.website` | The website linked from the listing | `https://franklinbarbecue.com/` |
| `place.plus_code` | Google's plus code for the location | `77C9+2F Austin, Texas` |
| `hours[]` | Opening hours per weekday | `{ "day": "Tuesday", "hours_range": "11 AM-3 PM" }` |
| `rating_summary.average_rating` | The place's overall rating | `4.7` |
| `rating_distribution[]` | Review count for each star level | `{ "stars": 4, "review_count": 690 }` |
| `reviews[].reviewer_name` | Name shown on each top review | `D. D.` |
| `reviews[].star_rating` | Stars given in that review | `5` |
| `reviews[].relative_date` | When it was posted, as Maps words it | `3 months ago` |
| `reviews[].review_text` | The review body | `Long queue but worth the wait…` |

For review text, owner responses and review dates across many places, the [Google Maps reviews scraper](/scrape/google-maps-reviews) page goes deeper on the same place-page response.

## How to scrape Google Maps with Zenrows

1. **Create a free Zenrows account** and copy your API key from the dashboard.
2. **Write the search as a Maps URL.** `https://www.google.com/maps/search/` followed by the query with `+` between words, with the place type and the area in the query: `coffee+shops+in+austin+tx`, `dentists+near+brooklyn+ny`.
3. **Open single places with a name and address search.** A query that matches one business, such as `Franklin+Barbecue+900+E+11th+St+Austin+TX`, lands on that place's page and returns the full place record: address, phone, website, hours and reviews.
4. **Send it with the default configuration**: Adaptive Stealth Mode to open the page, Extract to return the fields, and the country of the area you search so labels and formats match local results.
5. **Run every city and category in Batch.** One URL per area and business type, with an ID such as `coffee-austin` on each task, then request the place pages of the businesses you keep.

```python Python
# pip install requests
import json
import requests

params = {
    "apikey": "YOUR_ZENROWS_API_KEY",
    "url": "https://www.google.com/maps/search/coffee+shops+in+austin+tx",
    "mode": "auto",          # Adaptive Stealth Mode
    "extract": "auto",       # structured JSON
    "proxy_country": "us",   # results as a local searcher sees them
}
response = requests.get("https://api.zenrows.com/v1/", params=params, timeout=180)
response.raise_for_status()

places = response.json()["parsed"]["place_results"]
for place in places:
    print(place["name"], place["rating"], place["review_count"])
print(json.dumps(places[0], indent=2))
```

```javascript Node.js
// Node 18+ (built-in fetch)
const params = new URLSearchParams({
  apikey: "YOUR_ZENROWS_API_KEY",
  url: "https://www.google.com/maps/search/coffee+shops+in+austin+tx",
  mode: "auto",
  extract: "auto",
  proxy_country: "us",
});

const response = await fetch(`https://api.zenrows.com/v1/?${params}`, {
  signal: AbortSignal.timeout(180_000),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);

const { parsed } = await response.json();
for (const p of parsed.place_results) console.log(p.name, p.rating, p.review_count);
```

```bash cURL
curl "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.google.com%2Fmaps%2Fsearch%2Fcoffee%2Bshops%2Bin%2Baustin%2Btx&mode=auto&extract=auto&proxy_country=us"

# A single place, keeping only its contact details and hours
curl "https://api.zenrows.com/v1/?apikey=YOUR_ZENROWS_API_KEY&url=https%3A%2F%2Fwww.google.com%2Fmaps%2Fsearch%2FFranklin%2BBarbecue%2B900%2BE%2B11th%2BSt%2BAustin%2BTX%3Fhl%3Den&mode=auto&extract=auto&proxy_country=us&extract_fields=place.name%2Cplace.address%2Cplace.phone%2Cplace.website%2Chours"
```

```python Python SDK
# pip install zenrows
from zenrows import ZenRowsClient

client = ZenRowsClient("YOUR_ZENROWS_API_KEY")
response = client.get(
    "https://www.google.com/maps/search/Franklin+Barbecue+900+E+11th+St+Austin+TX?hl=en",
    params={"mode": "auto", "extract": "auto", "proxy_country": "us"},
)
parsed = response.json()["parsed"]
print(parsed["place"]["name"], parsed["place"]["phone"], parsed["rating_summary"]["average_rating"])
for day in parsed["hours"]:
    print(day["day"], day["hours_range"])
```

## Input

The scraper takes one Google Maps URL per request: a search for many places or a search that resolves to one place. The query in the URL decides the category and the area, so a lead list for fifty cities is fifty URLs with the settings below.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `url` | string | required | A Maps search such as `https://www.google.com/maps/search/coffee+shops+in+austin+tx`, or a name plus address search that opens one place |
| `mode` | string | `auto` | Adaptive Stealth Mode: starts with the lightest setup and adds rendering and protected-site handling only when Maps needs them |
| `extract` | string | `auto` | Returns `place_results` for a search, and `place`, `hours`, `rating_summary`, `rating_distribution` and `reviews` for a place |
| `extract_fields` | string | all fields | Comma-separated paths to keep, such as `place.name,place.phone,place.website,hours` |
| `proxy_country` | string | any | Two-letter country code. Use the country of the area you search, so the language, number formats and nearby results are local |
| `wait_for` | string | none | A CSS selector to wait for before the page is read |
| `session_id` | integer | none | Keep the same session for up to 10 minutes across related requests |

```json Batch input
{
  "type": "regular",
  "status": "closed",
  "zenrows_params": {
    "mode": "auto",
    "extract": "auto",
    "proxy_country": "us"
  },
  "tasks": [
    { "url": "https://www.google.com/maps/search/coffee+shops+in+austin+tx", "external_id": "coffee-austin" },
    { "url": "https://www.google.com/maps/search/barbecue+restaurants+in+austin+tx", "external_id": "bbq-austin" },
    { "url": "https://www.google.com/maps/search/Franklin+Barbecue+900+E+11th+St+Austin+TX?hl=en", "external_id": "franklin-barbecue" }
  ]
}
```

## Output

Every response is JSON with two keys: `html`, the page as Maps rendered it, and `parsed`, the structured record. A search and a place page return different groups. Both samples below are trimmed outputs of live requests made on Oct 20, 2026.

```json Search results
{
  "search_query": null,
  "place_results": [
    {
      "name": "Epoch Coffee",
      "cuisine": "Coffee shop",
      "rating": 4.5,
      "review_count": "2,538",
      "featured_review_snippet": null,
      "price_range": null,
      "place_id": null,
      "thumbnail_url": null
    },
    {
      "name": "Jo's Coffee - South Congress",
      "cuisine": "Coffee shop",
      "rating": 4.4,
      "review_count": "2,005",
      "featured_review_snippet": null,
      "price_range": null,
      "place_id": null,
      "thumbnail_url": null
    },
    {
      "name": "Idlewild Coffee",
      "cuisine": "Coffee shop",
      "rating": 5,
      "review_count": "48",
      "featured_review_snippet": null,
      "price_range": null,
      "place_id": null,
      "thumbnail_url": null
    }
  ],
  "web_results": [],
  "discussion_threads": [],
  "trending_posts": []
}
```

```json Place page
{
  "place": {
    "name": "Franklin Barbecue",
    "category": "Barbecue restaurant",
    "address": "900 E 11th St, Austin, TX 78702",
    "phone": "(512) 653-1187",
    "website": "https://franklinbarbecue.com/",
    "plus_code": "77C9+2F Austin, Texas"
  },
  "hours": [
    { "day": "Monday", "hours_range": "Closed" },
    { "day": "Tuesday", "hours_range": "11 AM-3 PM" },
    { "day": "Saturday", "hours_range": "11 AM-3 PM" }
  ],
  "rating_summary": { "average_rating": 4.7, "total_reviews": null },
  "rating_distribution": [
    { "stars": 4, "review_count": 690 },
    { "stars": 3, "review_count": 282 },
    { "stars": 2, "review_count": 103 },
    { "stars": 1, "review_count": 199 }
  ],
  "reviews": [
    {
      "reviewer_name": "D. D.",
      "star_rating": 5,
      "relative_date": "Edited 5 months ago",
      "review_text": "Brother and I came to Austin to eat and Franklin was our first stop. Didn't have time to wait so we pre ordered the minimum five pounds of meat…",
      "owner_response_text": null,
      "owner_response_date": null
    },
    {
      "reviewer_name": "A. S.",
      "star_rating": 5,
      "relative_date": "3 months ago",
      "review_text": "Franklin Barbecue feels like a place where the anticipation is part of the experience. The line outside can be long…",
      "owner_response_text": null,
      "owner_response_date": null
    }
  ]
}
```

The search list joins to the place page by name: request the place page for each listing you keep, and the full record comes back with the same name. Review counts in a search arrive as printed (`10,982`), so remove the separator before loading them as integers. To get a spreadsheet, flatten `place_results` with `pd.json_normalize(...)` and write CSV or Excel.

## Scrape Google Maps from your coding agent

Claude Code, Cursor, Codex and any MCP client can search Google Maps and read places as JSON from a prompt.

The agent runs the same Fetch and Extract request shown above: it searches an area, reads `place_results`, then opens the place pages it needs for phones, websites and hours. Connect the Zenrows MCP server once, or install the CLI and let the agent call it from the terminal.

```bash Connect the MCP server (Claude Code)
claude mcp add zenrows -e ZENROWS_API_KEY=YOUR_ZENROWS_API_KEY -- npx -y @zenrows/mcp
```

```json MCP config (Cursor, Claude Desktop, Windsurf)
{
  "mcpServers": {
    "zenrows": {
      "command": "npx",
      "args": ["-y", "@zenrows/mcp"],
      "env": { "ZENROWS_API_KEY": "YOUR_ZENROWS_API_KEY" }
    }
  }
}
```

```bash Or run the CLI
npx -y @zenrows/cli init
zenrows extract "https://www.google.com/maps/search/coffee+shops+in+austin+tx" --proxy-country us
```

```text Then ask your agent
Use Zenrows to search Google Maps for coffee shops in Austin, TX.
Keep the places rated 4.7 or higher with at least 200 reviews, then
open each one and return a table with name, address, phone, website
and Saturday opening hours.
```

## Scrape Google Maps at scale with Batch and Crawl

**Batch** covers a territory. Split it into one search per city or neighborhood and category, run them as one job, and every result comes back with your ID, such as `coffee-austin`. Deduplicate places by name and address, then send a second Batch of place pages for the businesses you keep. Smaller areas in the query return places a city-wide search would leave out.

**Crawl** picks up where Maps stops. `place.website` gives the business's own site; start a crawl there, keep the links that contain `contact`, `about`, `menu` or `locations`, and you get the pages with services, menus and other branches, the data a Maps listing does not carry.

```bash Batch (cURL)
curl -X POST "https://async.api.zenrows.com/v1/jobs" \
  -H "X-API-Key: YOUR_ZENROWS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "regular",
    "status": "closed",
    "zenrows_params": { "mode": "auto", "extract": "auto", "proxy_country": "us" },
    "tasks": [
      { "url": "https://www.google.com/maps/search/coffee+shops+in+austin+tx", "external_id": "coffee-austin" },
      { "url": "https://www.google.com/maps/search/coffee+shops+in+round+rock+tx", "external_id": "coffee-round-rock" },
      { "url": "https://www.google.com/maps/search/Franklin+Barbecue+900+E+11th+St+Austin+TX?hl=en", "external_id": "franklin-barbecue" }
    ]
  }'

# Read the results when the job finishes
curl "https://async.api.zenrows.com/v1/jobs/JOB_ID/results?status=successful" \
  -H "X-API-Key: YOUR_ZENROWS_API_KEY"
```

```bash Batch (CLI)
# areas.jsonl: one {"url": "...", "external_id": "...", "extract": "auto"} per line
zenrows batch create areas.jsonl --proxy-country us --wait
zenrows batch results <job-id> --out google-maps-places.jsonl
```

```bash Crawl (cURL)
curl -X POST "https://api.zenrows.com/v1/crawls" \
  -H "X-API-Key: YOUR_ZENROWS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://franklinbarbecue.com/",
    "depth": 2,
    "max_pages": 50,
    "include_patterns": ["contact", "about", "menu", "locations"]
  }'
```

**Scheduled jobs** run the same Batch job on a timetable, on Zenrows' side: every few hours, once a day, at set times on chosen days, or once at a future date. Each run keeps its own results, a webhook can tell your app when a run finishes, and you can pause or resume the schedule at any time, with no cron server to keep alive.

```bash Scheduled job (cURL)
# Runs every day on Zenrows' side; each run keeps its own results
curl -X POST "https://async.api.zenrows.com/v1/jobs" \
  -H "X-API-Key: YOUR_ZENROWS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "type": "scheduled",
      "status": "closed",
      "schedule": {
        "rate": {
          "every": 1,
          "unit": "day"
        }
      },
      "zenrows_params": {
        "mode": "auto",
        "extract": "auto",
        "proxy_country": "us"
      },
      "tasks": [
        {
          "url": "https://www.google.com/maps/search/coffee+shops+in+austin+tx",
          "external_id": "google-maps"
        }
      ]
    }'

# Or at set times: "schedule": { "calendar": { "times_of_day": ["09:00"],
#   "cadence": { "weekly": { "days": ["mon", "thu"] } } }, "timezone": "Europe/Madrid" }
```

## What teams do with Google Maps data

| Use case | Data they pull | Who runs it |
|---|---|---|
| Local lead lists | Name, category, address, phone and website for every business of a type in each city | Sales and growth teams, agencies |
| Market and site selection | Count, ratings and review volume of competitors per neighborhood | Retail, franchise and real estate analysts |
| Local SEO and listing audits | Category, hours, phone and website on Maps against the business's own records | Multi-location brands and local SEO agencies |
| Reputation tracking | Average rating, star distribution and newest reviews per location, over time | CX and operations teams |
| Competitor monitoring | Opening hours, ratings and review growth of nearby rivals | Restaurant groups and service businesses |
| Data enrichment | Phone, website and plus code to fill gaps in a CRM or a company table | RevOps and data teams |
| AI local assistants | Place records for a question like "open now near me", as JSON or Markdown | AI and product teams |

## Tips for scraping Google Maps

- **Put the area in the query.** `coffee+shops+in+austin+tx` returns Austin places from any request location. A query without a place, such as `coffee+shops`, returns places around wherever Maps thinks you are.
- **Split big areas into small ones.** A search returns the places Maps lists for that view. To cover a metro, run one search per neighborhood, suburb or ZIP code and deduplicate by name and address.
- **Reach one place with name plus address.** `/maps/search/Franklin+Barbecue+900+E+11th+St+Austin+TX` opens that business directly. The street address keeps chains and same-name businesses apart.
- **Add `hl=en` for stable labels.** Weekday names, categories and hours follow the interface language. Fixing the language keeps `hours[].day` and `place.category` in one language across countries.
- **Use the `place.website` domain as your key.** Names change and chains repeat; the website domain or the address is the safer join to your CRM.
- **Convert review dates on the day you scrape.** Maps prints `3 months ago`. Store the scrape date with each review so you can turn relative dates into calendar dates later.
- **Read the star distribution, not only the average.** `rating_distribution` shows whether a 4.7 comes from steady fours or from many fives and a block of one-star reviews.

## Frequently asked questions

### Is it legal to scrape Google Maps?

Business listings on Google Maps, such as names, addresses, phone numbers, hours and ratings, are public and shown to every visitor, and collecting them for lead lists or market research is common practice. Reviews carry reviewers' names, which count as personal data under laws such as the GDPR and the CCPA, so keep only what you have a legitimate reason to use. Check Google's terms for your use case and ask your lawyer if you are unsure.

### Is there an official Google Maps API?

Yes, the Places API in Google Maps Platform. Text Search returns at most 60 places per query, Place Details returns up to five reviews per place, every call is metered, and Google's terms limit how long you can store most of the data. A scraper reads the Maps pages themselves, so you keep the records and choose how many areas you search.

### What Google Maps pages can I scrape?

Searches ( google.com/maps/search/… ) for any category and area, and single places reached through a name and address search. Each search returns a list of places; each place returns its contact details, hours, rating distribution and top reviews.

### Can I scrape Google Maps reviews?

Yes. A place page returns its top reviews with reviewer name, star rating, relative date, text and the owner's reply when there is one, plus the rating distribution. The Google Maps reviews scraper page covers review collection in detail.

### Can I get phone numbers and websites from Google Maps?

Yes, for the businesses that list them. place.phone and place.website come from the place page, so search first, then request the place page of each business you want contact details for.

### How many places can I scrape from Google Maps?

Each search returns the places Maps lists for that query and area. To collect more, search smaller areas or narrower categories, one URL each, and run them as a Batch job. One Batch job accepts more than 10,000 URLs, inline or as a CSV file.

### How do I scrape Google Maps with Python?

Send a GET request to https://api.zenrows.com/v1/ with your API key, the Maps URL, Adaptive Stealth Mode and Extract turned on, as in the Python example above. response.json()["parsed"] returns place_results for a search and place , hours and reviews for a place. The zenrows package on PyPI wraps the same request.

### Can I scrape Google Maps without coding?

Yes. Ask an AI agent connected to the Zenrows MCP server for the places you want, or call Zenrows from n8n, Make or Zapier and send the rows to Google Sheets. Both run the same request as the code above.

### Can AI agents scrape Google Maps with Zenrows?

Yes. Connect the Zenrows MCP server to Claude, Cursor, Codex or any MCP client, or give your agent the Zenrows CLI. Ask for a category in a city and the agent searches Maps, filters the places and opens the ones it needs.

### Can I scrape Google Maps on a schedule?

Yes. Create a scheduled Batch job with your Google Maps URLs and the same settings as a single request, and Zenrows runs it on its side: every few hours, once a day, at set times on chosen days, or once at a future date. Each run keeps its own results, a webhook can notify your app when a run finishes, and the schedule can be paused or resumed at any time.

### Which integrations work with the Google Maps scraper?

Zenrows works with n8n, Make, Zapier, Clay, Dify, LangChain, LlamaIndex, CrewAI and Mastra, plus the Python, Node.js and Go SDKs and any HTTP client. Clay is a common destination for Maps lead lists. See the integrations page for the full list.

### What format does the data come in?

JSON by default, with the structured record in parsed and the rendered page in html . You can also ask for the page as Markdown or plain text for an LLM, or flatten the JSON into CSV and Excel.

## More Google Maps scrapers

- [Google Maps reviews scraper](https://www.zenrows.com/scrape/google-maps-reviews.md)

All scrapers: https://www.zenrows.com/scrape. Start free: https://app.zenrows.com/register. Docs: https://docs.zenrows.com
