Google Maps Reviews Scraper - Ratings and Text, No API Key
Pricing
from $0.27 / 1,000 review scrapeds
Google Maps Reviews Scraper - Ratings and Text, No API Key
Scrape Google Maps reviews from a place link, place ID, CID or business name. Each row has the star rating, full text, exact date, reviewer, owner reply and photos. It keeps paging until it has what you asked for, or Google runs out. No API key. $0.27 per 1,000 reviews, flat.
Pricing
from $0.27 / 1,000 review scrapeds
Rating
5.0
(2)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
34
Total users
22
Monthly active users
20 hours ago
Last modified
Categories
Share
Google Maps Reviews Scraper: every review for a place, no API key
Paste a Maps link, a place ID, a CID or just the business name, and get the reviews back as rows. Star rating, the full text, the exact date, who wrote it, whether the owner replied, and any photos attached. It keeps paging rather than stopping at the first screen.
Google itself is the limit, not the actor. A very large place hands out several thousand reviews and then stops issuing pages, so nobody can pull the complete history of a busy restaurant.
| Input | Maps links, place IDs, CIDs or business names, up to 50 per run |
| Output | One row per review |
| Ceiling | 5,000 reviews per run |
| Account needed | None, and no Google API key |
| Price | $0.27 per 1,000 reviews, flat on every plan |
🔍 What Google Maps Reviews Scraper does
It takes whatever form of a place you happen to have and resolves it to the same place. A copied
address-bar URL, a maps.app.goo.gl short link, a ChIJ… place ID, a numeric CID, or the plain
name of the business. Then it reads the review list, paging until it has what you asked for or
Google stops handing out pages.
You can point it at up to 50 places in one run and set a total row budget. That budget is split evenly between the places, so a chain audit gives you a comparable sample from every branch rather than all of it from the busiest one.
Reviews only. Opening hours, phone number, address, category and the overall star average are not part of this actor's output. The Google Maps Scraper linked below covers place details.
📥 What you give it
{"placeUrls": ["https://maps.app.goo.gl/abc123"],"maxReviews": 300,"maxReviewsPerPlace": 100,"sort": "newest","language": "en"}
| Field | Default | What it is |
|---|---|---|
placeUrls | none | Maps links, short links, place IDs or numeric CIDs. Up to 50. Paste the link exactly as the address bar gives it. |
searchTerms | none | Business names, if you do not have links. Up to 50, and each resolves to Google's top match. |
maxReviews | box starts at 20 | Total across every place in the run, split evenly between them. Up to 5,000. |
maxReviewsPerPlace | none | Optional cap per place, on top of the even split. Useful when one branch has 40,000 reviews and you want the newest hundred from each. |
sort | newest | newest, relevant, highest or lowest. |
reviewsSince | none | Only reviews after this point. See the warning below. |
onlyWithText | off | Skip star-only ratings with no words. |
language | en | Which language Google should translate into. |
country | us | Which country's Google to ask. |
proxyUrls | none | Optional. Your own servers, used exactly as given. |
reviewsSince only understands two formats: a number of days like 30 days or 30d, or a real
date like 2026-01-15. Anything else, including 2 weeks and 1 month, is ignored without
complaint, and the run then pulls and bills the full history up to your caps. Use days or a date.
reviewsSince stops paging early only when sort is newest. On any other order the cutoff
still filters rows, but the run reads further to find them.
📤 What you get back
A real row from a recent run, trimmed where the URLs run long:
{"ok": true,"charged": true,"recordType": "review","placeName": "Starbucks Reserve Roastery","placeUrl": "https://www.google.com/maps?cid=7899526995152106350","placeId": "ChIJsU30zM1qkFQRbnOm1_LBoG0","cid": "7899526995152106350","reviewId": "Ci9DQUlRQUNvZENodHljRjlvT21GRFdtSnpUV2xQYjFvM1kxbFRZMHhWVlRSMFRWRRAB","rating": 5,"text": "It's gone ):","originalText": null,"language": "en","publishedAt": "2025-09-26T17:40:32.007Z","relativeDate": "11 months ago","reviewerName": "Daniel J","reviewerUrl": "https://www.google.com/maps/contrib/103952951038275342964/reviews?hl=en-US","reviewerReviewsCount": 142,"reviewerPhotosCount": 625,"isLocalGuide": true,"ownerReply": "Hi there! We're so glad you had a wonderful experience. Thanks for sharing it with us!","ownerReplyRelativeDate": "11 months ago","reviewPhotosCount": 1,"reviewPhotoUrls": ["https://lh3.googleusercontent.com/grass-cs/..."],"scrapedAt": "2026-09-21T01:45:28.154Z"}
| Field | What it is |
|---|---|
publishedAt | A real timestamp, worked back from Google's relative wording. relativeDate keeps the original "11 months ago". |
reviewId | Stable. Use it as your dedupe key across runs. |
target | Exactly what you typed for this place, so you can join results back to your own list. |
text, originalText | text is in the language you asked for. originalText holds the writer's own wording when a translation happened, and null when none did. |
ownerReply | The owner's response, or null. |
isLocalGuide | The badge as true or false. Google's numeric level is not published here. |
placeName | null when you gave a bare ID or CID and Google returned no label. Everything else on the row still identifies the place. |
reviewPhotoUrls | Up to 10 per review. |
🧾 Reading the output
Three kinds of row can land in your dataset.
| Row | How to spot it | Charged |
|---|---|---|
| A review | charged: true and a reviewId | yes |
| The sample row | _sample: true | no |
| A diagnostic | _diagnostic: true and an errorCode | no |
Filter on _sample and _diagnostic being absent, not on recordType. The free sample row
also carries recordType: "review", so a filter on that alone keeps it.
The errorCode on a diagnostic row tells you which target had the problem:
| Code | What it means |
|---|---|
NO_PLACE_FOUND | That business name matched nothing. Use its link or place ID instead. |
NO_REVIEWS | The place resolved but has no reviews, or none survived your filters. |
SHORTLINK_UNRESOLVED | A maps.app.goo.gl link would not expand. Open it once in a browser and paste the full URL. |
PLACE_ID_UNRESOLVED | The ID did not resolve to a place. |
TIME_BUDGET | The run ran out of time. Everything already delivered is complete. |
PROXY_INPUT_ADJUSTED | A network setting in your input was not usable, so the run used its own. |
NETWORK | Google was unreachable or answered badly. Re-run it. |
One bad target never stops the others, and a diagnostic row never fails the run.
▶️ How to run it
- Open Google Maps Reviews Scraper and click Try for free.
- Paste one or more links into Place links or IDs, or type names into Business names.
- Set Maximum reviews. Start around 20 to see the output shape.
- Pick a Review order and a Language if the defaults do not suit you, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it from the Apify API.
💰 How much does it cost?
$0.27 per 1,000 reviews. Flat on every Apify plan, no volume tiers.
You pay per review row delivered. Reviews dropped by reviewsSince or onlyWithText, duplicates,
sample rows and diagnostic rows are all free, and a place with no reviews costs you nothing.
💡 What people use it for
- Watching what changed in a place's reviews since last month, on a schedule, using
reviewsSince. - Auditing every branch of a chain on the same terms, with a per-place cap so one busy site does not eat the budget.
- Pulling the text of everything below three stars to find the complaint that keeps repeating.
- Checking which reviews the owner replied to, and how fast, across a set of competitors' locations.
🚧 What it does not do
- Reviews only. No opening hours, phone number, address, category, star average or total review count.
- Not the full history. Google stops issuing pages after a few thousand on large places, and the hard ceiling here is 5,000 per run regardless.
- Sorting is Google's, applied before paging. Asking for 20 sorted "highest" gives you the 20 highest Google serves first, not a true sort of the whole history.
- Star-only ratings have no text, so
textisnullon those unless you switch on Skip star-only ratings. - Translation is Google's, and its quality is not something this actor controls.
- Photo links are Google CDN URLs. Stable for a long time, but not archival.
- A name matching several places resolves to Google's top match, and a name with no city in it can land on the wrong branch. For a specific place, use its link or place ID.
- Rows are a snapshot. A review can be edited or deleted later, and
scrapedAtrecords when it was read. - The row budget splits evenly between your places. A place with fewer reviews than its share returns fewer rows, and the leftover is not handed to the others.
🧭 Which Google scraper do you need?
| If you want | Use |
|---|---|
| Reviews for places you can name or link | This one |
| Place details, and reviews alongside them | Google Maps Scraper |
| Reviews plus AI-drafted replies, on a schedule | Google Reviews Monitor |
| App store reviews instead | Google Play Reviews Scraper |
| Search results | Google Search Results Scraper |
❓ Questions people ask
Do I need a Google API key? No. Nothing to apply for, no quota to manage.
Can I monitor a place over time? Yes. Schedule it with reviewsSince set to something like
7 days and sort on newest, and each run picks up only what is new. reviewId makes deduping
across runs straightforward.
Why did I get fewer reviews than I asked for? Either the place does not have that many, or Google stopped issuing pages. You are charged for what arrived.
Why is my date cutoff being ignored? Almost always the format. reviewsSince takes 30 days,
30d or a date like 2026-01-15. Wordings like 2 weeks are dropped silently.
Can I audit every branch of a chain? Feed the list of place IDs, set maxReviewsPerPlace, and
you get a comparable sample from each branch in one run.
Is scraping Google reviews legal? These are public reviews on public place pages. They contain personal data all the same, which GDPR and similar laws cover, so have a reason for collecting it. Apify's write-up on scraping and the law is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the place link and the run ID. The errorCode on
the diagnostic row usually names the problem on its own.