How to scrape Google Maps results with Python

Get places, ratings, review counts and contact details from Google Maps as JSON, why the official Places API gets expensive, and what a Maps search actually costs. With a tested example, August 2026.

You want the businesses Google Maps shows for a query: names, ratings, review counts, addresses, phone numbers, websites. This post covers the three ways to get them, with real numbers for what each one costs, and a Python example that we ran before publishing.

Why not the official Places API?

The official route exists and is the right answer for some products, but three properties surprise people at the point where it is too late to change course:

  1. Price. Text Search on the Places API costs $32.00 per 1,000 requests on the Pro tier, checked on Google’s pricing page on 20 October 2026, with 5,000 free calls a month. The unit price only starts dropping meaningfully past 100,000 monthly requests.
  2. Result caps. A Text Search returns at most 60 places over three pages. For “restaurants in a city” style queries the map interface knows far more than the API will give you.
  3. Licensing. Places data comes with restrictions on storing and displaying it. If your use case is building a lead list or a dataset, the terms are the real constraint, not the code.

The DIY alternative, driving a headless browser over the Maps interface, breaks for the same reasons scraping Google Search breaks: IP blocks, rotating obfuscated markup, and a scroll-to-load results panel that needs a real browser session per query. It is a maintenance project, not a script.

The version that works

Send the query to an API that owns the browsers and the parsing, and get JSON back:

import requests

API_KEY = "faf_live_..."  # your FastAF key

resp = requests.get(
    "https://api.fastaf.co/v1/maps",
    params={
        "query": "best pizza in Naples Italy",
        "page": 0,
    },
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=60,
)
resp.raise_for_status()

for place in resp.json()["search_results"]:
    print(f'{place["rating"]}  ({place["reviews"]:>6})  {place["title"]}')

We ran exactly this request while writing this post (August 2026). It returned 20 places for 5 credits, the first being L’Antica Pizzeria da Michele: rating 4.3, 54,724 reviews, price range, address, phone number, website, opening state and GPS coordinates, all as plain JSON fields. No browser, no proxies, no parsing.

What fields do you get per place?

Each entry in search_results carries the business data the Maps panel shows:

Field Example from our test run
title L’Antica Pizzeria da Michele
rating / reviews 4.3 / 54724
type, types Pizza restaurant, Italian restaurant, …
price €1–10
address Via Cesare Sersale, 1, 80139 Napoli NA, Italy
phone +39 392 …
website the business’s own site
open_state Closed · Opens 10:30 AM
gps_coordinates latitude / longitude
place_id, data_id stable identifiers for follow-up lookups

Two parameters worth knowing beyond query: ll pins the search to coordinates and zoom (@40.85,14.26,14z) so you control the map viewport instead of letting the query text guess it, and page moves through result pages, roughly 20 places at a time, past the official API’s 60-place ceiling.

What does a Maps search cost?

A Google Maps search on FastAF costs 5 credits, the same as a Google Search request. On the Scale pack ($99 for 300,000 credits) that is 60,000 Maps searches, or $1.65 per 1,000. The same 60,000 searches on the official Places API Text Search at $32.00 per 1,000 come to $1,760 (55,000 billed after the 5,000 free calls of the month), and return at most 60 places each.

The free tier is 500 credits with no card, which is 100 Maps searches, enough to check field coverage on your actual queries before deciding anything. Failed requests are never billed: credits are reserved when a request starts and returned if it does not come back with a result.

Lead lists: the practical loop

The most common use of this endpoint is local lead generation. The loop is: search a category in a city, filter on the fields, and you have a qualified list in minutes:

def places(query, pages=3):
    for page in range(pages):
        resp = requests.get(
            "https://api.fastaf.co/v1/maps",
            params={"query": query, "page": page},
            headers={"Authorization": f"Bearer {API_KEY}"},
            timeout=60,
        )
        resp.raise_for_status()
        yield from resp.json()["search_results"]

# Businesses with real traction but no website: classic web-agency prospects.
leads = [
    p for p in places("dentist in Austin TX")
    if p.get("reviews", 0) > 50 and not p.get("website")
]

Three pages of one query is 15 credits. A 50-city sweep of the same category at three pages each is 750 credits, about $0.29 on the Growth pack: the follow-up emails will cost you more than the data.