How to Collect Google Maps Data for Research and Analysis
The hard part is not getting listings. It is getting all of them, once each, with categories that mean the same thing everywhere.
- Author
- HuiTu Technology
- Published
- Updated
Map platforms hold the most complete public record of where businesses are. Getting a few listings out of one is easy. Getting a complete, deduplicated, consistently categorised set for a whole metro area is a different task, and the difference is where most projects go wrong.
Start by choosing the right route
There are three ways to obtain this data, and they suit different situations. Choosing badly at the start is expensive to correct later.
| Route | Best for | Main constraint |
|---|---|---|
| Official Places API | Production features, ongoing use, small volumes | Cost at scale, and licence terms restrict storage and redistribution |
| Licensed data provider | Multi-country coverage with guarantees | Price, and coverage that varies by market |
| Collecting public listings | One-off research at metro or national scale | Requires care with access limits and terms; not suitable for every purpose |
Tile the search area, do not search by name
The most common cause of an incomplete dataset is searching for a city by name. Every search interface returns a bounded number of results per query, so a single query for restaurants in a large city returns a few dozen out of several thousand, weighted towards the centre and towards prominence.
The fix is to tile. Cover the study area with overlapping cells small enough that no cell contains more results than a single query can return, then query each cell separately and merge. Cell size has to adapt to density: a grid fine enough for a city centre wastes thousands of queries on farmland.
# Adaptive tiling: split any cell that returns a full page of results
def collect(cell, depth=0, max_depth=5):
results = query(cell)
if len(results) >= PAGE_LIMIT and depth < max_depth:
# The cell is saturated, so we are almost certainly missing records
return [r for quad in cell.split_into_quads()
for r in collect(quad, depth + 1, max_depth)]
return resultsThe rule is simple: if a cell returns a full page, assume it is truncated and subdivide it. Stop when cells return fewer results than the page limit, or when you hit a depth cap. This one technique is the difference between 40% and 95% coverage.
Decide the fields before you start
- Name, and a normalised form of the name for matching later.
- Category, plus the original source label kept separately.
- Full address, parsed into street, city, region and postcode.
- Latitude and longitude, six decimal places is plenty.
- Phone and website, where the business publishes them.
- Rating and review count, as a popularity proxy rather than a quality measure.
- Opening hours, normalised into a structured weekly schedule.
- Status, so permanently closed venues do not inflate your counts.
- A collection timestamp on every single record.
Deduplicate on a documented key
Overlapping tiles mean the same venue appears in several queries. Platform identifiers handle most of it, but merging a second source, or re-running months later, needs a real business key: normalised name plus address, with a distance threshold for near matches.
Write the rule down and deliver it with the data. A deduplication rate is a headline statistic in any market comparison, and an undocumented one makes the comparison worthless.
Validate before you analyse
- Plot everything. Points in the sea or in a neighbouring country appear immediately and are always errors.
- Count identical coordinates. Clusters mean geocoding fell back to a centroid.
- Compare the category distribution against expectations. A category holding most of the dataset means the mapping is wrong.
- Spot-check fifty records by hand against the source. It takes twenty minutes and catches parsing errors nothing else will.
- Check coverage at the edges of your study area, where tiling most often fails.
- Restaurants · 34
- Cafés · 22
- Retail · 26
If you need it more than once
Build for repetition from the start. Keep a stable identifier per venue, store each run separately rather than overwriting, and produce a change log of added, removed and modified records. Openings and closures are frequently the most valuable output, and you can only see them if you kept the previous run.