DEV Community

Cecilia Hill
Cecilia Hill

Posted on

How to Collect Google Maps Local Results with a SERP API and Python

Local search data is useful, but collecting it reliably is harder than it looks.

For example, say you want to know which businesses show up when someone searches:

coffee shop in Austin
Enter fullscreen mode Exit fullscreen mode

or:

dentist near me
Enter fullscreen mode Exit fullscreen mode

or:

plumber in London
Enter fullscreen mode Exit fullscreen mode

You may want the business name, ranking position, rating, address, phone number, website, or map result URL.

At first, it sounds like a simple scraping task.

Open Google Maps.

Search a keyword.

Extract the results.

Save them to a file.

But in practice, Google Maps and local search results are dynamic, location-sensitive, and hard to parse consistently. Results can change by country, city, language, device, and search intent. Pages may also load content dynamically, which makes simple HTML scraping unreliable.

That is why many developers use a SERP API instead.

In this tutorial, we will build a simple Python script that collects Google Maps local results through a SERP API and saves the data into a CSV file.

The workflow looks like this:

Local search query → SERP API → structured JSON → Python parser → CSV file
Enter fullscreen mode Exit fullscreen mode

What we are building

We will create a Python script that:

  1. Sends a local search query to a SERP API
  2. Gets structured JSON results back
  3. Extracts business names, positions, ratings, addresses, and websites
  4. Saves the results into a CSV file

Example query:

coffee shop in Austin
Enter fullscreen mode Exit fullscreen mode

Example output:

position,business_name,rating,reviews,address,phone,website
1,Example Coffee,4.6,812,123 Main St Austin TX,+1 000-000-0000,https://example.com
2,Another Coffee Bar,4.4,391,456 Market St Austin TX,+1 111-111-1111,https://example.org
Enter fullscreen mode Exit fullscreen mode

This kind of data is useful for:

  • local SEO tracking
  • competitor monitoring
  • agency reporting
  • market research
  • lead generation workflows
  • location-based business analysis
  • AI agents that need local search context

Why not scrape Google Maps directly?

You can scrape Google Maps directly, but it usually becomes difficult once the workflow runs regularly.

Some common problems:

  • dynamic page rendering
  • changing layouts
  • blocked requests
  • CAPTCHA
  • location mismatch
  • inconsistent result fields
  • browser automation overhead
  • parsing failures
  • retry and monitoring logic

If your goal is to build a local SEO report or competitor monitoring workflow, maintaining a Google Maps scraper is probably not your core product.

You usually want structured data.

For example:

{
  "local_results": [
    {
      "position": 1,
      "title": "Example Coffee",
      "rating": 4.6,
      "reviews": 812,
      "address": "123 Main St, Austin, TX",
      "phone": "+1 000-000-0000",
      "website": "https://example.com"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

This format is much easier to use in a database, dashboard, spreadsheet, or AI workflow.

What a SERP API does

A SERP API collects search engine results and returns them in a structured format, usually JSON.

Instead of controlling a browser or parsing raw HTML, you send parameters such as:

  • search query
  • search engine
  • country
  • city or location
  • language
  • device
  • output format

Then the API returns structured results.

For local search, the response may include fields such as:

  • business name
  • position
  • rating
  • number of reviews
  • address
  • phone
  • website
  • category
  • map link
  • latitude and longitude
  • opening hours

The exact field names depend on the provider, but the idea is the same: you get structured local search data without maintaining your own scraper.

You can test this workflow with providers such as SerpApi, SearchAPI, Bright Data, or Talordata. In this example, I’ll use a generic SERP API request pattern. Replace the endpoint and parameter names with the provider you use.

Disclosure: I work with Talordata, so treat any mention of it as disclosed. Talordata is one option worth testing if you need geo-targeted SERP data, JSON / HTML output, and local search results for SEO, competitor tracking, or market research workflows.

Install dependencies

We only need two Python packages:

pip install requests python-dotenv
Enter fullscreen mode Exit fullscreen mode

requests is used to call the API.

python-dotenv is optional, but useful for loading API keys from a .env file.

Create a .env file

Create a file named .env:

SERP_API_KEY=your_api_key_here
SERP_API_URL=https://your-serp-api-endpoint.example.com/search
Enter fullscreen mode Exit fullscreen mode

Do not hardcode your API key directly in the script.

Basic API request

Create a file named local_maps_search.py.

import os
import requests
from dotenv import load_dotenv


load_dotenv()

SERP_API_KEY = os.getenv("SERP_API_KEY")
SERP_API_URL = os.getenv("SERP_API_URL")


def fetch_local_results(query, location="Austin, Texas, United States", language="en"):
    if not SERP_API_KEY:
        raise ValueError("Missing SERP_API_KEY environment variable")

    if not SERP_API_URL:
        raise ValueError("Missing SERP_API_URL environment variable")

    params = {
        "api_key": SERP_API_KEY,
        "engine": "google_maps",
        "q": query,
        "location": location,
        "language": language,
        "output": "json",
    }

    response = requests.get(SERP_API_URL, params=params, timeout=30)
    response.raise_for_status()

    return response.json()


if __name__ == "__main__":
    data = fetch_local_results("coffee shop in Austin")
    print(data)
Enter fullscreen mode Exit fullscreen mode

Run it:

python local_maps_search.py
Enter fullscreen mode Exit fullscreen mode

At this point, you should receive a JSON response from your SERP API provider.

Again, the exact endpoint and parameters depend on the provider. Some APIs may use google_maps, maps, local, or another engine name. Check your provider’s documentation and adjust the parameters.

Extract local business results

Different SERP APIs may use different response keys.

Common names include:

  • local_results
  • maps_results
  • places_results
  • results

To make the script more flexible, we can write a helper function that checks several possible keys.

def get_local_items(data):
    possible_keys = [
        "local_results",
        "maps_results",
        "places_results",
        "results",
    ]

    for key in possible_keys:
        value = data.get(key)
        if isinstance(value, list):
            return value

    return []
Enter fullscreen mode Exit fullscreen mode

Now we can extract useful fields.

def normalize_place(item):
    return {
        "position": item.get("position") or item.get("rank"),
        "business_name": item.get("title") or item.get("name"),
        "rating": item.get("rating"),
        "reviews": item.get("reviews") or item.get("review_count"),
        "address": item.get("address"),
        "phone": item.get("phone"),
        "website": item.get("website") or item.get("link"),
        "category": item.get("category") or item.get("type"),
        "map_link": item.get("map_link") or item.get("maps_url"),
    }
Enter fullscreen mode Exit fullscreen mode

This gives us a cleaner structure that is easier to store.

Print the top results

Update the script:

import os
import requests
from dotenv import load_dotenv


load_dotenv()

SERP_API_KEY = os.getenv("SERP_API_KEY")
SERP_API_URL = os.getenv("SERP_API_URL")


def fetch_local_results(query, location="Austin, Texas, United States", language="en"):
    if not SERP_API_KEY:
        raise ValueError("Missing SERP_API_KEY environment variable")

    if not SERP_API_URL:
        raise ValueError("Missing SERP_API_URL environment variable")

    params = {
        "api_key": SERP_API_KEY,
        "engine": "google_maps",
        "q": query,
        "location": location,
        "language": language,
        "output": "json",
    }

    response = requests.get(SERP_API_URL, params=params, timeout=30)
    response.raise_for_status()

    return response.json()


def get_local_items(data):
    possible_keys = [
        "local_results",
        "maps_results",
        "places_results",
        "results",
    ]

    for key in possible_keys:
        value = data.get(key)
        if isinstance(value, list):
            return value

    return []


def normalize_place(item):
    return {
        "position": item.get("position") or item.get("rank"),
        "business_name": item.get("title") or item.get("name"),
        "rating": item.get("rating"),
        "reviews": item.get("reviews") or item.get("review_count"),
        "address": item.get("address"),
        "phone": item.get("phone"),
        "website": item.get("website") or item.get("link"),
        "category": item.get("category") or item.get("type"),
        "map_link": item.get("map_link") or item.get("maps_url"),
    }


if __name__ == "__main__":
    data = fetch_local_results(
        query="coffee shop in Austin",
        location="Austin, Texas, United States",
    )

    local_items = get_local_items(data)
    places = [normalize_place(item) for item in local_items]

    for place in places[:10]:
        print(place["position"], place["business_name"], place["rating"], place["address"])
Enter fullscreen mode Exit fullscreen mode

Example output:

1 Example Coffee 4.6 123 Main St, Austin, TX
2 Another Coffee Bar 4.4 456 Market St, Austin, TX
3 Downtown Coffee House 4.5 789 Congress Ave, Austin, TX
Enter fullscreen mode Exit fullscreen mode

Save results to CSV

For local SEO or competitor monitoring, CSV is often enough for a first version.

Add this helper function:

import csv


def save_to_csv(rows, filename="local_results.csv"):
    fieldnames = [
        "position",
        "business_name",
        "rating",
        "reviews",
        "address",
        "phone",
        "website",
        "category",
        "map_link",
    ]

    with open(filename, mode="w", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=fieldnames)
        writer.writeheader()

        for row in rows:
            writer.writerow(row)
Enter fullscreen mode Exit fullscreen mode

Then call it at the end:

save_to_csv(places, "austin_coffee_shops.csv")
print("Saved results to austin_coffee_shops.csv")
Enter fullscreen mode Exit fullscreen mode

Full script:

import os
import csv
import requests
from dotenv import load_dotenv


load_dotenv()

SERP_API_KEY = os.getenv("SERP_API_KEY")
SERP_API_URL = os.getenv("SERP_API_URL")


def fetch_local_results(query, location="Austin, Texas, United States", language="en"):
    if not SERP_API_KEY:
        raise ValueError("Missing SERP_API_KEY environment variable")

    if not SERP_API_URL:
        raise ValueError("Missing SERP_API_URL environment variable")

    params = {
        "api_key": SERP_API_KEY,
        "engine": "google_maps",
        "q": query,
        "location": location,
        "language": language,
        "output": "json",
    }

    response = requests.get(SERP_API_URL, params=params, timeout=30)
    response.raise_for_status()

    return response.json()


def get_local_items(data):
    possible_keys = [
        "local_results",
        "maps_results",
        "places_results",
        "results",
    ]

    for key in possible_keys:
        value = data.get(key)
        if isinstance(value, list):
            return value

    return []


def normalize_place(item):
    return {
        "position": item.get("position") or item.get("rank"),
        "business_name": item.get("title") or item.get("name"),
        "rating": item.get("rating"),
        "reviews": item.get("reviews") or item.get("review_count"),
        "address": item.get("address"),
        "phone": item.get("phone"),
        "website": item.get("website") or item.get("link"),
        "category": item.get("category") or item.get("type"),
        "map_link": item.get("map_link") or item.get("maps_url"),
    }


def save_to_csv(rows, filename="local_results.csv"):
    fieldnames = [
        "position",
        "business_name",
        "rating",
        "reviews",
        "address",
        "phone",
        "website",
        "category",
        "map_link",
    ]

    with open(filename, mode="w", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=fieldnames)
        writer.writeheader()

        for row in rows:
            writer.writerow(row)


if __name__ == "__main__":
    query = "coffee shop in Austin"
    location = "Austin, Texas, United States"

    data = fetch_local_results(query=query, location=location)
    local_items = get_local_items(data)

    places = [normalize_place(item) for item in local_items]

    save_to_csv(places, "austin_coffee_shops.csv")

    print(f"Saved {len(places)} results to austin_coffee_shops.csv")
Enter fullscreen mode Exit fullscreen mode

Collect results for multiple cities

Local results change by location.

That is why a single query is often not enough.

For example, “coffee shop” in Austin and “coffee shop” in Seattle will return different results.

You can loop through multiple locations:

locations = [
    "Austin, Texas, United States",
    "Seattle, Washington, United States",
    "New York, New York, United States",
]

query = "coffee shop"

all_rows = []

for location in locations:
    data = fetch_local_results(query=query, location=location)
    local_items = get_local_items(data)

    for item in local_items:
        row = normalize_place(item)
        row["query"] = query
        row["location"] = location
        all_rows.append(row)

save_to_csv(all_rows, "coffee_shops_by_city.csv")
Enter fullscreen mode Exit fullscreen mode

If you add query and location to the CSV, update the fieldnames list:

fieldnames = [
    "query",
    "location",
    "position",
    "business_name",
    "rating",
    "reviews",
    "address",
    "phone",
    "website",
    "category",
    "map_link",
]
Enter fullscreen mode Exit fullscreen mode

Now you can compare local rankings across cities.

Common local SEO use cases

Once you have structured local results, you can build many useful workflows.

Track competitors

You can monitor which businesses appear for service keywords in a city.

Example:

dentist in Austin
emergency plumber in Chicago
personal injury lawyer in Miami
Enter fullscreen mode Exit fullscreen mode

Compare rankings by location

A business may rank well in one city but not another.

Local search data helps you compare visibility across markets.

Build agency reports

Agencies can collect local results weekly or monthly and generate reports for clients.

Feed local search data into AI agents

An AI agent can use local search data to summarize competitors, identify top businesses, or create market research reports.

Monitor new entrants

If a new business starts appearing in local results, you can detect it early.

What to check before choosing a SERP API

Before choosing a provider, test it with your actual local search queries.

Do not only test one easy keyword.

Try different query types:

coffee shop in Austin
dentist near me
plumber in London
best hotel near Times Square
restaurant in Singapore
Enter fullscreen mode Exit fullscreen mode

Then check:

  • Does the API return clean JSON?
  • Are local results included?
  • Are ratings and review counts available?
  • Does geo-targeting work correctly?
  • Can you control country, city, and language?
  • Are failed requests billed?
  • How much cleanup is needed before saving the data?
  • Does the response work for your reporting or AI workflow?

If you are comparing tools like SerpApi, SearchAPI, Bright Data, or Talordata, the most useful test is simple: run the same local queries across providers and compare the response body.

The best API is the one that gives your application usable local data with the least extra work.

Final thoughts

Collecting Google Maps local results is not just a scraping task.

It is a data quality problem.

You need the right query, the right location, stable fields, structured output, and a workflow that can run more than once.

A SERP API helps by turning local search results into JSON that your application can use directly.

With Python, you can collect local results, normalize fields, save them to CSV, and use the data for local SEO, competitor monitoring, agency reporting, market research, or AI agents.

If you want to test this workflow, Talordata is one option worth comparing. It supports structured SERP data, JSON / HTML response formats, geo-targeted results, and search workflows for SEO monitoring, competitor tracking, market research, and AI applications.

Talordata also offers 1,000 free API requests after signup, which is enough to test real local search queries before committing to a provider.

Top comments (0)