How to Scrape Google Maps Search Results with TalorData
Learn how to scrape Google Maps search results with TalorData SERP API. This technical guide covers Maps parameters, Python requests, local business fields, ratings, reviews, addresses, phone numbers, websites, place IDs, coordinates, CSV export, and local SEO workflows.
Google Maps results are local-intent data. They show which businesses appear for a query, where they rank, how strong their reputation looks, and what contact details are visible.
If you are building local SEO tools, lead generation workflows, market research dashboards, competitor monitors, or AI agents, Google Maps data can help answer questions like:
|
Question |
Why it matters |
|
Which businesses appear for “dentist near me”? |
Local visibility |
|
Which competitor ranks higher around a specific coordinate? |
Local SEO tracking |
|
Which businesses have strong ratings and review counts? |
Reputation analysis |
|
Which listings have phone numbers and websites? |
Lead enrichment |
|
Which areas are crowded with competitors? |
Market research |
|
Which listings appear in multiple cities? |
Expansion planning |
|
Which local results should an AI agent recommend? |
AI workflow context |
In this guide, we will build a Python workflow that sends Google Maps queries to TalorData, receives structured JSON, extracts useful business fields, and exports the results to CSV.
The final workflow looks like this:
Search query + map location
↓
TalorData SERP API
↓
Google Maps results in JSON
↓
Parse business fields
↓
Normalize place data
↓
Export to CSV or database
What does scraping Google Maps search results mean?
In this article, “scraping Google Maps” means collecting structured Google Maps-style search results through TalorData’s SERP API.
It does not mean controlling a browser, scrolling manually, or scraping HTML from the Google Maps interface.
The goal is to collect fields such as:
|
Field |
Example |
|
Business name |
Blue Bottle Coffee |
|
Position |
1 |
|
Rating |
4.5 |
|
Review count |
1,240 |
|
Category |
Coffee shop |
|
Address |
123 Example St, New York |
|
Phone number |
+1 212-000-0000 |
|
Website |
https://example.com |
|
Google Maps URL |
Maps listing link |
|
Place ID / data CID |
Unique place reference |
|
Latitude / longitude |
Map coordinates |
|
Opening status |
Open now / closed |
|
Price level |
$, $$, $$$ |
TalorData Google Maps responses are designed for local business search workflows and can include fields such as business name, place ID, address, coordinates, category, rating, review count, rank position, opening status, phone number, website, Google Maps URL, thumbnail, and price level when available.
When should you use the Google Maps SERP API?
Use Google Maps search results when your question is about local visibility.
|
Use case |
Example |
|
Local SEO rank tracking |
Track “plumber near me” around different coordinates |
|
Lead generation |
Collect local businesses with phone and website |
|
Competitor research |
Compare ratings, reviews, and positions |
|
Market analysis |
Count businesses in a category by city |
|
Franchise monitoring |
Check brand visibility across markets |
|
Review intelligence |
Track rating and review count signals |
|
AI agents |
Feed local business options into recommendations |
Google Maps rankings are location-sensitive. A query from one coordinate may return a different set of businesses than the same query a few blocks away. That is why location control matters.
Core Google Maps parameters
Start with these parameters.
|
Parameter |
Required |
Purpose |
Example |
|
|
Yes |
Select Google Maps search |
|
|
|
For search queries |
Business, category, or local intent query |
|
|
|
Recommended for map search |
Latitude, longitude, and zoom |
|
|
|
Optional |
Search mode |
|
|
|
For place lookup |
Specific Google Maps place reference |
|
|
|
For place lookup |
Google CID-style place reference |
|
|
|
Optional |
Google domain |
|
|
|
Optional |
Interface language |
|
|
|
Optional |
Country context |
|
|
|
Optional |
Freshness control |
|
For Google Maps requests, ll uses a coordinate format like @latitude,longitude,scale, and the Maps search type supports search-style and place-style workflows.
Search mode vs place mode
You will usually use one of two patterns.
Search mode
Use search mode when you want a list of businesses.
Examples:
coffee shops near Manhattan
dentists in Austin
hotels near JFK Airport
plumbers in Chicago
restaurants near Times Square
A search request needs a query and location context.
{
"engine": "google_maps",
"type": "search",
"q": "coffee shops",
"ll": "@40.7455096,-74.0083012,14z",
"hl": "en",
"gl": "us"
}
Place mode
Use place mode when you want details for one known place.
You can use a place_id or data_cid from a previous Maps result.
{
"engine": "google_maps",
"type": "place",
"place_id": "ChIJExamplePlaceId",
"hl": "en",
"gl": "us"
}
A common workflow is:
Search query
↓
Get local business results
↓
Extract place_id or data_cid
↓
Request place details
↓
Store richer business data
Step 1: Set up your API key
Store your TalorData API key and endpoint as environment variables.View the setup guide>>
export TALORDATA_API_KEY="your_api_key_here"
export TALORDATA_SERP_ENDPOINT="your_talordata_serp_endpoint_here"
On Windows PowerShell:
setx TALORDATA_API_KEY "your_api_key_here"
setx TALORDATA_SERP_ENDPOINT "your_talordata_serp_endpoint_here"
Install Python dependencies:
pip install requests pandas
Step 2: Create a reusable Python client
This function sends a Google Maps search request and returns JSON.
Adjust the endpoint or authentication format if your TalorData account uses a different request style.
import os
import requests
from typing import Any, Dict, Optional
TALORDATA_API_KEY = os.getenv("TALORDATA_API_KEY")
TALORDATA_SERP_ENDPOINT = os.getenv("TALORDATA_SERP_ENDPOINT")
def fetch_google_maps(
query: str,
ll: str,
hl: str = "en",
gl: str = "us",
google_domain: str = "google.com",
no_cache: bool = True,
extra_params: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
"""
Fetch Google Maps search results with TalorData SERP API.
ll format example:
@40.7455096,-74.0083012,14z
"""
if not TALORDATA_API_KEY:
raise RuntimeError("Missing TALORDATA_API_KEY environment variable.")
if not TALORDATA_SERP_ENDPOINT:
raise RuntimeError("Missing TALORDATA_SERP_ENDPOINT environment variable.")
payload: Dict[str, Any] = {
"engine": "google_maps",
"type": "search",
"q": query,
"ll": ll,
"hl": hl,
"gl": gl,
"google_domain": google_domain,
"no_cache": no_cache
}
if extra_params:
payload.update(extra_params)
headers = {
"Authorization": f"Bearer {TALORDATA_API_KEY}",
"Content-Type": "application/json"
}
response = requests.post(
TALORDATA_SERP_ENDPOINT,
json=payload,
headers=headers,
timeout=30
)
response.raise_for_status()
return response.json()
Run a basic search:
if __name__ == "__main__":
data = fetch_google_maps(
query="coffee shops",
ll="@40.7455096,-74.0083012,14z",
hl="en",
gl="us"
)
print(data)
Step 3: Inspect the raw response
Before writing a parser, inspect the JSON.
import json
print(json.dumps(data, indent=2, ensure_ascii=False)[:5000])
Look for result arrays such as:
local_results
maps_results
place_results
results
organic_results
The exact field name can vary by response type. Do not carve your parser into stone too early. First check the cave wall, then bring the chisel.
Step 4: Parse Google Maps results
Here is a defensive parser that checks several possible result containers and extracts common local business fields.
from typing import Any, Dict, List
def get_first_available_list(data: Dict[str, Any], keys: List[str]) -> List[Dict[str, Any]]:
for key in keys:
value = data.get(key)
if isinstance(value, list):
return value
return []
def parse_maps_results(data: Dict[str, Any]) -> List[Dict[str, Any]]:
items = get_first_available_list(
data,
keys=[
"local_results",
"maps_results",
"place_results",
"results",
"organic_results"
]
)
rows = []
for index, item in enumerate(items, start=1):
gps = item.get("gps_coordinates") or {}
links = item.get("links") or {}
rows.append({
"position": item.get("position", index),
"title": item.get("title") or item.get("name"),
"place_id": item.get("place_id"),
"data_cid": item.get("data_cid") or item.get("cid"),
"category": item.get("type") or item.get("category"),
"rating": item.get("rating"),
"review_count": item.get("reviews") or item.get("review_count"),
"address": item.get("address"),
"phone": item.get("phone"),
"website": item.get("website") or links.get("website"),
"maps_url": item.get("link") or item.get("maps_url"),
"thumbnail": item.get("thumbnail"),
"price_level": item.get("price") or item.get("price_level"),
"open_state": item.get("open_state") or item.get("hours"),
"latitude": gps.get("latitude") or item.get("latitude"),
"longitude": gps.get("longitude") or item.get("longitude")
})
return rows
Use it:
data = fetch_google_maps(
query="coffee shops",
ll="@40.7455096,-74.0083012,14z"
)
rows = parse_maps_results(data)
for row in rows[:5]:
print(row["position"], row["title"], row["rating"], row["review_count"])
Step 5: Save results to CSV
import pandas as pd
data = fetch_google_maps(
query="coffee shops",
ll="@40.7455096,-74.0083012,14z"
)
rows = parse_maps_results(data)
df = pd.DataFrame(rows)
df.to_csv("google_maps_results.csv", index=False)
print(df.head())
A CSV table may look like this:
|
position |
title |
rating |
review_count |
category |
address |
|
1 |
Example Coffee |
4.6 |
1280 |
Coffee shop |
123 Example St |
|
2 |
Sample Cafe |
4.4 |
760 |
Cafe |
45 Sample Ave |
|
3 |
Local Roasters |
4.7 |
420 |
Coffee roasters |
88 Market Rd |
Step 6: Add search context
A Maps result without context is hard to compare later.
Always store the query, coordinate, language, country, and timestamp with every row.
from datetime import datetime, timezone
def add_search_context(
rows: List[Dict[str, Any]],
query: str,
ll: str,
hl: str,
gl: str
) -> List[Dict[str, Any]]:
collected_at = datetime.now(timezone.utc).isoformat()
for row in rows:
row["query"] = query
row["ll"] = ll
row["hl"] = hl
row["gl"] = gl
row["collected_at"] = collected_at
return rows
Usage:
query = "coffee shops"
ll = "@40.7455096,-74.0083012,14z"
hl = "en"
gl = "us"
data = fetch_google_maps(query=query, ll=ll, hl=hl, gl=gl)
rows = parse_maps_results(data)
rows = add_search_context(rows, query=query, ll=ll, hl=hl, gl=gl)
pd.DataFrame(rows).to_csv("google_maps_snapshot.csv", index=False)
Now you can compare results over time.
|
Change |
Meaning |
|
Position changed |
Local ranking changed |
|
Rating changed |
Reputation changed |
|
Review count increased |
More customer feedback |
|
Business disappeared |
Ranking or availability changed |
|
New competitor appeared |
Market movement |
|
Website added or removed |
Listing completeness changed |
Step 7: Search multiple coordinates
For local SEO, one city-level search is often too broad.
A better workflow is to test the same query across a coordinate grid.
locations = [
{
"name": "Manhattan West",
"ll": "@40.7455096,-74.0083012,14z"
},
{
"name": "Times Square",
"ll": "@40.758896,-73.985130,14z"
},
{
"name": "Lower Manhattan",
"ll": "@40.707491,-74.011276,14z"
}
]
all_rows = []
for location in locations:
data = fetch_google_maps(
query="coffee shops",
ll=location["ll"],
hl="en",
gl="us"
)
rows = parse_maps_results(data)
for row in rows:
row["grid_location"] = location["name"]
rows = add_search_context(
rows,
query="coffee shops",
ll=location["ll"],
hl="en",
gl="us"
)
all_rows.extend(rows)
pd.DataFrame(all_rows).to_csv("google_maps_grid_results.csv", index=False)
This helps you detect:
|
Signal |
Example |
|
Local rank variation |
A cafe ranks #1 near one coordinate and #8 near another |
|
Competitor clusters |
Many competitors appear around one neighborhood |
|
Visibility gaps |
A business disappears outside a small radius |
|
Review advantage |
Competitors with stronger reviews rank more often |
|
Expansion areas |
Underserved areas with fewer strong listings |
Step 8: Fetch place-level details
A search result gives you a list. A place lookup gives you a deeper look at one business.
Use place_id or data_cid from the search result.
def fetch_google_maps_place(
place_id: Optional[str] = None,
data_cid: Optional[str] = None,
hl: str = "en",
gl: str = "us",
google_domain: str = "google.com"
) -> Dict[str, Any]:
if not place_id and not data_cid:
raise ValueError("Provide either place_id or data_cid.")
payload: Dict[str, Any] = {
"engine": "google_maps",
"type": "place",
"hl": hl,
"gl": gl,
"google_domain": google_domain
}
if place_id:
payload["place_id"] = place_id
if data_cid:
payload["data_cid"] = data_cid
response = requests.post(
TALORDATA_SERP_ENDPOINT,
json=payload,
headers={
"Authorization": f"Bearer {TALORDATA_API_KEY}",
"Content-Type": "application/json"
},
timeout=30
)
response.raise_for_status()
return response.json()
Example:
rows = parse_maps_results(data)
first_place_id = rows[0].get("place_id")
place_data = fetch_google_maps_place(place_id=first_place_id)
print(json.dumps(place_data, indent=2, ensure_ascii=False)[:3000])
Use place mode when you need to enrich a specific business after discovering it in search results.
Step 9: Build a complete script
Here is a complete script that searches Google Maps, parses local business fields, adds context, and exports to CSV.
import os
import json
import requests
import pandas as pd
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional
TALORDATA_API_KEY = os.getenv("TALORDATA_API_KEY")
TALORDATA_SERP_ENDPOINT = os.getenv("TALORDATA_SERP_ENDPOINT")
def fetch_google_maps(
query: str,
ll: str,
hl: str = "en",
gl: str = "us",
google_domain: str = "google.com",
no_cache: bool = True,
extra_params: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
if not TALORDATA_API_KEY:
raise RuntimeError("Missing TALORDATA_API_KEY environment variable.")
if not TALORDATA_SERP_ENDPOINT:
raise RuntimeError("Missing TALORDATA_SERP_ENDPOINT environment variable.")
payload: Dict[str, Any] = {
"engine": "google_maps",
"type": "search",
"q": query,
"ll": ll,
"hl": hl,
"gl": gl,
"google_domain": google_domain,
"no_cache": no_cache
}
if extra_params:
payload.update(extra_params)
response = requests.post(
TALORDATA_SERP_ENDPOINT,
json=payload,
headers={
"Authorization": f"Bearer {TALORDATA_API_KEY}",
"Content-Type": "application/json"
},
timeout=30
)
response.raise_for_status()
return response.json()
def get_first_available_list(data: Dict[str, Any], keys: List[str]) -> List[Dict[str, Any]]:
for key in keys:
value = data.get(key)
if isinstance(value, list):
return value
return []
def parse_maps_results(data: Dict[str, Any]) -> List[Dict[str, Any]]:
items = get_first_available_list(
data,
keys=[
"local_results",
"maps_results",
"place_results",
"results",
"organic_results"
]
)
rows = []
for index, item in enumerate(items, start=1):
gps = item.get("gps_coordinates") or {}
links = item.get("links") or {}
rows.append({
"position": item.get("position", index),
"title": item.get("title") or item.get("name"),
"place_id": item.get("place_id"),
"data_cid": item.get("data_cid") or item.get("cid"),
"category": item.get("type") or item.get("category"),
"rating": item.get("rating"),
"review_count": item.get("reviews") or item.get("review_count"),
"address": item.get("address"),
"phone": item.get("phone"),
"website": item.get("website") or links.get("website"),
"maps_url": item.get("link") or item.get("maps_url"),
"thumbnail": item.get("thumbnail"),
"price_level": item.get("price") or item.get("price_level"),
"open_state": item.get("open_state") or item.get("hours"),
"latitude": gps.get("latitude") or item.get("latitude"),
"longitude": gps.get("longitude") or item.get("longitude")
})
return rows
def add_search_context(
rows: List[Dict[str, Any]],
query: str,
ll: str,
hl: str,
gl: str
) -> List[Dict[str, Any]]:
collected_at = datetime.now(timezone.utc).isoformat()
for row in rows:
row["query"] = query
row["ll"] = ll
row["hl"] = hl
row["gl"] = gl
row["collected_at"] = collected_at
return rows
def main() -> None:
query = "coffee shops"
ll = "@40.7455096,-74.0083012,14z"
hl = "en"
gl = "us"
raw_data = fetch_google_maps(
query=query,
ll=ll,
hl=hl,
gl=gl
)
rows = parse_maps_results(raw_data)
rows = add_search_context(rows, query=query, ll=ll, hl=hl, gl=gl)
pd.DataFrame(rows).to_csv("google_maps_results.csv", index=False)
with open("raw_google_maps_response.json", "w", encoding="utf-8") as file:
json.dump(raw_data, file, ensure_ascii=False, indent=2)
print(f"Saved {len(rows)} rows to google_maps_results.csv")
print("Saved raw_google_maps_response.json")
if __name__ == "__main__":
main()
What fields should you store?
For most Google Maps scraping workflows, start with this schema:
{
"query": "coffee shops",
"ll": "@40.7455096,-74.0083012,14z",
"hl": "en",
"gl": "us",
"collected_at": "2026-06-30T09:00:00Z",
"business": {
"position": 1,
"title": "Example Coffee",
"place_id": "ChIJExample",
"data_cid": "123456789",
"category": "Coffee shop",
"rating": 4.6,
"review_count": 1280,
"address": "123 Example St, New York, NY",
"phone": "+1 212-000-0000",
"website": "https://example.com",
"maps_url": "https://...",
"latitude": 40.7455,
"longitude": -74.0083,
"open_state": "Open",
"price_level": "$$"
}
}
For advanced workflows, add:
|
Field |
Use case |
|
|
UI display |
|
|
Business availability |
|
|
Restaurant or service filters |
|
|
Demand pattern analysis |
|
|
Reputation intelligence |
|
|
Review management |
|
|
Conversion tracking |
|
|
Restaurant intelligence |
|
|
Classification |
|
|
Debugging and reprocessing |
Common mistakes
Mistake 1: Searching without coordinates
For Maps, location is not a decoration. Use ll when you need local precision.
Mistake 2: Comparing results from different zoom levels
A query at 14z may produce different results than the same query at 16z. Store the full ll value.
Mistake 3: Treating rating alone as quality
A 4.8 rating with 12 reviews is not the same as a 4.6 rating with 2,000 reviews. Track both rating and review count.
Mistake 4: Ignoring business identity
Names can vary. Use place_id or data_cid when possible for deduplication.
Mistake 5: Not saving raw JSON
During development, always store the raw response. It makes parser changes much easier.
Mistake 6: Forgetting timestamps
Maps data changes. A snapshot without time is a fossil with no museum label.
Final thoughts
Scraping Google Maps search results with TalorData is mainly about turning local search into structured data.
Start with a query, coordinate, language, country, and Google Maps search type. Then parse business name, position, rating, reviews, category, address, phone, website, place ID, coordinates, opening status, and Maps URL.
Once the data is structured, you can use it for local SEO, lead generation, competitor monitoring, market research, franchise tracking, and AI agents.
Google Maps is a living local marketplace. A good API workflow turns that marketplace into rows your systems can reason over.
FAQ
Can I scrape Google Maps search results with TalorData?
Yes. Use the google_maps engine with a local query and location context such as ll, then parse the returned business results into JSON, CSV, or your database.
What is the most important Google Maps parameter?
For local search precision, ll is one of the most important parameters because it defines the map coordinate and zoom context.
Should I use search mode or place mode?
Use search mode when you need a list of businesses for a query. Use place mode when you already have a place_id or data_cid and want details for one specific place.
What fields should I extract first?
Start with position, business name, category, rating, review count, address, phone, website, place ID, latitude, longitude, and Google Maps URL.