Skip to content

Google Places API With Python: Pull Business Leads Step by Step (2026)

Guide· 9 min read
Google Places API With Python: Pull Business Leads Step by Step (2026)

Key takeaways

  • The official way to get business data from Google Maps in code is the Places API (New) Text Search endpoint. One POST request returns up to 20 businesses.
  • You choose the fields with a field mask, and the fields you choose decide which price tier Google bills you at. Phone number, website and rating are in the more expensive tier.
  • One query returns at most 60 results across all pages, and the API returns no email addresses.
  • Google limits how long you may store most Places data. Read the current terms before you build a database on it.

If you can write a little Python, you can pull structured business data from Google Maps without scraping a page. Google offers an official endpoint for it, with clear limits and a price list. It will not give you everything a lead tool does, and this guide is straightforward about what is missing.

Below you will set up the API, understand the request, run a complete script that writes a CSV, and see where the approach stops being the best tool for the job.

What this gets you, and what it does not

  • You get: name, address, phone number, website, rating, review count, status (open or closed), coordinates and a stable place ID for each business returned.
  • You do not get: email addresses, owner names, social profiles or ad-pixel data. Those are not part of a Google listing.
  • Limits: each request returns at most 20 places, and Google documents a maximum of 60 results across all pages of a single query.

For phone and website data on a modest list, that is enough. For emails you need a second step that reads each website, which is what LeadOutreach's enrichment does.

Set up the API

  1. Create a project in the Google Cloud console and attach a billing account. The API will not run without one, even inside the free usage.
  2. Enable Places API (New) for the project.
  3. Create an API key and restrict it to the Places API, and to your IP address if you can. An unrestricted key that leaks can run up charges.
  4. Store the key in an environment variable, not in your code: export GOOGLE_MAPS_API_KEY=your-key.
  5. Install the one dependency: pip install requests.

The request in plain words

Text Search takes a plain-text query, the same kind you would type into Maps, such as dentist in Austin TX. You send it as a POST request to https://places.googleapis.com/v1/places:searchText with three headers: the content type, your API key in X-Goog-Api-Key, and a field mask in X-Goog-FieldMask.

The field mask is required and does two jobs. It tells Google which fields to return, and it decides your price tier. Fields such as name, address and location belong to the Pro tier. Phone number, website, rating and review count belong to the Enterprise tier, which costs more per request. Asking only for what you need keeps the bill down.

To get the next page of results, include nextPageToken in the field mask, then send the token back as pageToken in the next request with the same query. Google's documentation notes that all parameters other than the page size and token must stay identical between pages.

The complete script

import csv
import os
import requests

API_KEY = os.environ["GOOGLE_MAPS_API_KEY"]
ENDPOINT = "https://places.googleapis.com/v1/places:searchText"

# Phone, website and rating put these requests in the Enterprise price tier.
FIELD_MASK = ",".join([
    "places.id",
    "places.displayName",
    "places.formattedAddress",
    "places.businessStatus",
    "places.nationalPhoneNumber",
    "places.websiteUri",
    "places.rating",
    "places.userRatingCount",
    "nextPageToken",
])


def search(query, max_pages=3):
    """Yield places for one text query, following the pagination token."""
    body = {"textQuery": query, "pageSize": 20}
    for _ in range(max_pages):
        response = requests.post(
            ENDPOINT,
            json=body,
            headers={
                "Content-Type": "application/json",
                "X-Goog-Api-Key": API_KEY,
                "X-Goog-FieldMask": FIELD_MASK,
            },
            timeout=30,
        )
        response.raise_for_status()
        data = response.json()
        yield from data.get("places", [])

        token = data.get("nextPageToken")
        if not token:
            break
        body = {"textQuery": query, "pageSize": 20, "pageToken": token}


def to_row(place):
    return {
        "place_id": place.get("id", ""),
        "name": place.get("displayName", {}).get("text", ""),
        "address": place.get("formattedAddress", ""),
        "status": place.get("businessStatus", ""),
        "phone": place.get("nationalPhoneNumber", ""),
        "website": place.get("websiteUri", ""),
        "rating": place.get("rating", ""),
        "reviews": place.get("userRatingCount", ""),
    }


def main():
    queries = ["dentist in Austin TX", "dentist in Round Rock TX"]
    seen, rows = set(), []

    for query in queries:
        for place in search(query):
            if place["id"] in seen:
                continue  # the same business can appear in several queries
            seen.add(place["id"])
            if place.get("businessStatus") == "OPERATIONAL":
                rows.append(to_row(place))

    with open("leads.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=list(rows[0].keys()))
        writer.writeheader()
        writer.writerows(rows)
    print(f"Wrote {len(rows)} businesses to leads.csv")


if __name__ == "__main__":
    main()

Run it and read the result

Run python leads.py. Open leads.csv and check a handful of rows against Google Maps by hand. Look for closed businesses, missing websites and obvious duplicates. The script already skips anything that is not marked operational and removes repeat place IDs.

Two habits will save you money and trouble. Test with one query and one page first, and add a budget alert in the Cloud console before you scale up.

Get past the 60-result limit

A single query stops at 60 places, so a big city needs many queries. Split the area (neighbourhoods, postcodes, suburbs), vary the wording ("dentist", "dental clinic", "orthodontist"), and let the seen set remove overlaps. The Text Search request also accepts a location bias or restriction so you can point a query at a specific area; check Google's documentation for the shapes it accepts. The full approach, with a coverage checklist, is in why one Google Maps search never returns every business.

Costs and terms

Each page of results is a billable request. At the entry price of the Enterprise tier, Google's price list shows $35 per 1,000 requests, after 1,000 free requests a month, as last updated on 2026-09-17. Check the current list before you rely on it. The worked examples are in Places API pricing for lead lists.

Terms matter as much as price. Google's service terms limit how long you may store most Places content, with place IDs as the documented exception. If your plan is to build a permanent database of businesses, read the current Maps Platform terms first, and compare with the other route in Google Places API vs a Google Maps scraper.

When code is not the best tool

The API is a good fit if you enjoy the code, need official data and can live with no emails. It is a poor fit if you need verified emails, filters and a spreadsheet by tomorrow. A hosted tool covers that without a billing account or a script to maintain.

Try it on your own search
Skip the setup and get a filtered lead list with website emails from a single Google Maps search.
Start 7-Day Free Trial (1,000 Leads) →

Sources and further reading

Start Finding Verified Leads Today

Extract verified emails, phone numbers, and social links from Google Maps. Start with a 7-day Starter trial (1,000 leads included) and keep 100 free leads every month forever after. No credit card required.

Instant setup · No credit card required · 100 free leads/mo forever after

Related articles

FAQ

Frequently asked questions

There is free monthly usage for each price tier, and the IDs-only tier is unlimited, as shown on Google's price list. You still need a billing account, and usage beyond the free amount is charged. Phone number, website and rating fall in a more expensive tier than name and address.

No. Google listings do not include emails and the API does not return them. You need a separate step that reads each business website, or a tool that does it for you.

Up to 20 per request, and Google documents a maximum of 60 across all pages of a single query. To cover a large area, run several queries for different parts of it and remove duplicates by place ID.

Google's terms restrict how long most Places content can be stored, with place IDs as an exception. Read the current Google Maps Platform service terms before building a database on it.

No. The Places API (New) is a plain HTTPS endpoint, so the requests library is enough, as in the script above.