Google Maps Reviews Scraper — The Complete Review List
Pricing
from $0.48 / 1,000 reviews
Google Maps Reviews Scraper — The Complete Review List
The complete review list for a Google Maps business, not a sample of it. A Maps link or a place id returns every review newest first: text, star rating, posted and edited dates, the reviewer, attached photos and the owner reply. Star-only ratings are in there, so the total agrees with the page.
Pricing
from $0.48 / 1,000 reviews
Rating
0.0
(0)
Developer
The Netaji
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Share
Google Maps Reviews Scraper
Every review a Google Maps business has, in one dataset, rather than the first few pages of them. A Maps link or a place id goes in. Each review comes back newest first with its text, its star rating, when it was posted and when it was last edited, who wrote it, any photos they attached, and the business owner's public reply.
Star-only ratings are part of that list. Google counts them in the total it prints on a place's own
page, so keeping them is what makes the number in the dataset agree with the number a reader can see
for themselves: the largest place measured returned 5,950 reviews against the 5,950 Maps displays,
with no duplicate review_id anywhere in them.
What every row carries
| Field | What it holds |
|---|---|
review_id | Google's own id for the review, and the key to deduplicate on |
place_cid | The place the review belongs to, joining to a business row's cid |
stars | The rating given, 1 to 5 |
text | The review body, or null on a star-only rating |
language | The language Google detected the text to be in |
created_at, updated_at | Posted and last-edited instants, UTC |
created_at_us, updated_at_us | The same instants as Google's own microsecond integers |
relative_time | Google's own wording of the review's age, as Maps shows it |
author_name, author_id, author_profile_url, author_avatar | The reviewer |
author_review_count, author_photo_count, author_local_guide_level | The reviewer's own contribution statistics |
review_photos | Photos attached to the review, each with its link and pixel size |
owner_response_text, owner_response_at | The business owner's public reply |
place_ref | The place Google itself stamps on the review, used to verify the walk |
Switching on Add business details to every review adds place_name, place_address,
place_categories, place_rating, place_phone and place_website to every row of that place.
Accepted input
places is required and takes one or more Google Maps places. A place is either Google's own
identifier in 0x…:0x… form or a Maps link containing one; both are accepted, they may be mixed in
one list, and a link whose colon arrived percent-encoded from a copy-paste still resolves. A place
listed twice under two spellings is walked once.
maxItems caps how many rows the run saves and defaults to 100. Setting it to 0 removes the cap,
in which case the run continues to the end of the place's reviews.
cursor resumes a walk that stopped at the cap. It is described under Resuming a capped run.
enrichPlaceDetails defaults to false. When enabled, the business behind the reviews is looked up
once per place and its place_name, place_address, place_categories, place_rating,
place_phone and place_website are stamped onto every review row of that place. The lookup is one
extra call per place rather than per review, and it is billed once per place, only after it succeeds.
{"places": ["0x808587fb77f5f64d:0x25d564f177f99946"],"maxItems": 100,"enrichPlaceDetails": false}
Response fields
{"place_cid": "0x808587fb77f5f64d:0x25d564f177f99946","review_id": "ChZDSUhNMG9nS0VJQ0FnSURfeGV5RVh3EAE","stars": 5,"text": "Best espresso in the neighbourhood. Tiny room, huge care.","language": "en","created_at": "2025-05-14T12:00:00.000Z","updated_at": "2025-05-14T12:00:00.000Z","created_at_us": 1747224000000000,"updated_at_us": 1747224000000000,"relative_time": "3 months ago","author_name": "Alex Rivera","author_id": "112233445566778899000","author_profile_url": "https://www.google.com/maps/contrib/112233445566778899000","author_avatar": "https://lh3.googleusercontent.com/a/example=s120-c-rp-mo-br100","author_review_count": 87,"author_photo_count": 412,"author_local_guide_level": 7,"review_photos": null,"owner_response_text": null,"owner_response_at": null,"place_ref": "0x0:0x25d564f177f99946"}
Fields Google states nothing for are returned as null rather than omitted, so every row has the same
shape. review_id is Google's own identifier for the review and is the key to deduplicate on across
runs. place_cid is the place the row belongs to and joins to a business row's cid, which matters
when several places are walked in one run.
Resuming a capped run
When a run stops because maxItems was reached and the place has more reviews, the run log prints a
continue token. Passing that token back as cursor, with the same single place in places, resumes
the walk where it stopped.
A token belongs to the place it was issued for, so it is passed back exactly as it was printed,
including the part before the |. A token sent with a different place is refused before a request is
spent, and a token cannot be sent alongside more than one place. The reason is in the questions
below.
Questions
How is "every review" checked, rather than assumed?
Against the number Google Maps prints on the place's own page, which is independent of anything this
Actor can see. Four places were walked to the end and compared: 338 against a displayed 338, 1,722
against 1,723, 1,782 against 1,782, and 5,950 against 5,950. Across those 492 pages there were no
duplicate review_id values. The one missing review on the second place has no explanation beyond a
review being removed between the page being read and the count being taken.
Why is text null on some rows?
Because that row is a star-only rating rather than a broken row. It carries stars, an author and a
timestamp, and nothing else; 25 of 100 consecutive rows measured were of this kind, and across a
corpus they run to roughly 25 to 40 per cent of reviews. Maps counts them in the total it prints, so
filtering them out and then reporting a total produces a number that disagrees with the place's own
page. Filtering them for text analysis is reasonable; filtering them and then counting is not, and
the same applies to an average rating computed from the rest, because star-only rows are not a random
sample of opinions.
Why is there no sort option? Because every order except newest returns a strict subset. Walked once per sort on the same 338-review place, newest reached 338, most relevant reached 323, highest rating reached 143 and lowest rating reached 143. The union of all four is exactly 338, which is the newest set with nothing in it that newest did not already return. A sort option would therefore let a run lose 57 per cent of a place's reviews while every page still looked healthy. Sorting rows that have already arrived costs nothing.
What happens if a continue token is used with a different place? Nothing, because the pair is refused. That check exists because Google does not make it: a token replayed against another place answers with THAT place's reviews, starting partway down its list. The result is a full page of well-formed rows and the wrong answer to the question asked, which is harder to notice than an error would be.
Why did a run return fewer reviews than the place claims to have?
Either maxItems capped it, in which case the run log carries a continue token, or the place has
fewer reviews than the number being compared against. A short page is not the end of a walk: the last
page of the 338-review place held 18 rows and no continue token, so a run ends when Google declines to
issue a token rather than when a page comes back thin.
Why was the first request slow when the rest were fast? The reviews path needs a moment to get ready after an idle period, and that preparation can take around 35 seconds. It is then amortised over hundreds of requests, so a run that pages deeply pays it once. A run of a single small place pays it and then finishes, which makes the fixed cost look like the whole cost.
Can reviews be filtered by rating or date at the source?
No. Google's own filters are the sort orders above, and each of them truncates the corpus rather than
filtering it. The run returns everything and leaves filtering to the dataset, where stars and
created_at are both present on every row.
What happens when several places are listed?
Each place is walked to its own end before the next one starts, and each keeps its own continue
token; tokens are never carried across places. maxItems is one shared budget across the whole run,
so a first place with thousands of reviews can consume it before the second place is reached.
What happens on a place nobody has reviewed? The run finishes with zero rows rather than failing. An empty dataset here means the place has no reviews, not that the request failed.
Why is there no likes or "helpful" count on a review? Because nothing in the payload is one. The single unexplained per-row integer that could have been it behaves the wrong way for a helpfulness signal: Google's most-relevant ranking surfaces its LOW values rather than its high ones, with means of 17.6 against 33.9 on one place and 26.4 against 41.9 on another, and it sits inside the author block where an author statistic belongs. It is not published under a name it has not earned.
Why is relative_time sometimes at odds with the timestamps?
Because it is the string Maps itself shows, computed at the moment the page is read. It ages inside a
stored copy while created_at and updated_at do not, and it disagrees with them by design on an
edited review. It is there for display; sorting belongs on created_at.
Why are the timestamps published twice?
created_at_us and updated_at_us are Google's own integers, in microseconds since the epoch,
republished exactly as they arrive. created_at and updated_at are the same instants as UTC date
strings, for tools that cannot sort an integer of that size. The unit stays in the field name because
a microsecond timestamp read as milliseconds lands in the year 57,000 and looks like a successful
parse.
Why does the output not carry a review count for the place? Because the integer that looks like one is wrong. Measured against the count Maps displays it read 1,324 where Maps said 1,723, and 10,337 where Maps said 5,950, so it is not published anywhere in this family. Counting the rows this Actor returns is the reliable way to reach that number.
Does a complete walk cost more than a partial one? Yes, and star-only ratings are the reason it is worth saying. They are saved and billed like any other row, and they are a quarter to two-fifths of a corpus, so a place walked to the end costs noticeably more than the same place walked halfway. That is the trade behind the completeness claim.
Related Actors
Google Maps Scraper searches an area and returns
complete business records, each carrying the cid this Actor takes as a place. It is the way to
build a list of places to read reviews for.
Google Maps Place Scraper returns one business record per link or identifier, for cases where the business is wanted without its reviews.