Google Maps Reviews Scraper with Sentiment & Replies
Pricing
from $0.18 / 1,000 results
Google Maps Reviews Scraper with Sentiment & Replies
Scrape Google Maps reviews with star rating, text, date, reviewer name, owner-reply detection, reply latency in days and star-anchored sentiment. Filter unanswered or by star rating. Export to JSON, CSV or Excel. From $0.18 per 1,000 results.
Pricing
from $0.18 / 1,000 results
Rating
0.0
(0)
Developer
Alexandre Manguis
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
15 days ago
Last modified
Categories
Share
Google Maps Reviews Scraper with Sentiment & Owner-Reply Tracking
Scrape Google Maps reviews for any public place and get them back reputation-ready: star rating, text, date, reviewer info, owner-reply detection, reply latency in days, star-anchored sentiment, and a needsResponse flag — no post-processing code required. Export to JSON, CSV or Excel.
What it does
This Actor collects the publicly visible reviews shown on a Google Maps place page (one or many places per run) and, for each review, computes the fields a reputation-management workflow actually needs:
- Whether the owner replied, and how long it took (
ownerReplied,ownerReplyText,replyLatencyDays). Google exposes no exact timestamp for replies, only a coarse relative label (e.g. "a week ago");replyLatencyDaysis therefore an approximation whose error grows with the reply's age, andnullwhen it can't be placed reliably. - A sentiment label and score derived from the star rating (plus a lexicon fallback for common English words), so you don't need to call an LLM or a sentiment API per review.
- A
needsResponseflag:truewhen a review is negative/neutral and unanswered — the exact triage filter an agency needs. - Server-side filters (
onlyUnanswered,minStars/maxStars,reviewsNewerThan) so you pay only for the reviews that matter to you.
Most low-cost Google Maps review scrapers return the raw star/text/date dump and leave sentiment, reply-matching and latency to you. This Actor does that work locally, for free, as part of the same run.
Each run returns up to 60 of the newest reviews per place (Google's own review-list response is capped at 60 regardless of what you request — see FAQ). This is designed for recurring reputation monitoring (schedule a run + reviewsNewerThan), not a one-off full historical export.
Who is it for / use cases
- Reputation-management & local-SEO agencies tracking several client locations who need a weekly report: rating trend, sentiment mix, unanswered count, median reply latency.
- Multi-location businesses (restaurant, retail, clinic chains) that want to list every negative review with
ownerReplied=falseolder than N days, per location — an SLA tracking view. - AI reply-drafting / RAG pipeline builders who need clean, sentiment-tagged, reply-aware review data to feed an agent that drafts owner responses.
- Competitive benchmarking: compare sentiment mix and reply responsiveness of a business against nearby competitors' public reviews.
Features
- Collects reviews from one or many Google Maps place URLs in a single run.
- Sort by newest, most relevant, highest or lowest rating.
- Filter by star range, text-only reviews, unanswered reviews, or a minimum publish date (
reviewsNewerThan) — filtering happens before billing, so filtered-out rows are never charged. - Owner-reply detection with reply latency in days (approximate — see note above, Google gives no exact timestamp for replies).
- Local, rule-based sentiment (
positive/neutral/negative) anchored on the star rating, with a documented lexicon fallback — no external API cost, no per-review charge. - Data-minimisation default: reviewer profile URL and contribution count are
nullunless you explicitly opt in (includeReviewerProfile). - Structured skip rows (
skipped: true,skipReason, no billing event) for invalid URLs or places with zero reviews — the run still succeeds.
Input
| Field | Type | Default | Description |
|---|---|---|---|
placeUrls | array of string (required) | — | Google Maps place URLs to collect reviews from. Accepts both the ?q=place_id:... form and the @lat,lng/data=...!1s0x... form. |
maxReviewsPerPlace | integer | 50 | Max reviews collected per place, capped at 60: Google's review-list endpoint returns at most 60 reviews per response regardless of this value, and its pagination token does not work over plain HTTP (see FAQ). |
maxResults | integer | 200 | Hard cap on total reviews pushed to the dataset across all places. |
reviewsSort | enum: newest, relevant, highestRanking, lowestRanking | newest | Sort order requested from Google. |
reviewsNewerThan | string | — | Skip reviews older than this date (ISO date like 2026-09-01, or relative like 30 days). Pagination stops early when reviewsSort=newest. |
minStars / maxStars | integer 1–5 | — | Keep only reviews within this star range. |
onlyUnanswered | boolean | false | Keep only reviews with no public owner response. |
onlyWithText | boolean | false | Skip star-only reviews with no text. |
language | string (ISO 639-1) | en | Interface/response language requested from Google. |
computeSentiment | boolean | true | Compute sentiment locally. Disable for a pure raw dump. |
includeReviewerProfile | boolean | false | Include the reviewer's public profile URL and contribution count. Off by default for GDPR data minimisation. |
proxyConfiguration | object | {"useApifyProxy": true} | Apify Proxy settings. Datacenter proxy is sufficient for this target; escalate to residential only if you see repeated blocks. |
Output (real sample)
{"placeUrl": "https://www.google.com/maps/place/?q=place_id:ChIJrTLr-GyuEmsRBfy61i59si0","placeId": "ChIJrTLr-GyuEmsRBfy61i59si0","skipped": false,"skipReason": null,"reviewId": "Ci9DQUlRQUNvZENodHljRjlvT2xWdVUzTXlTbUY0U1hwSFF6SkNNbWx2YW1sdFZrRRAB","reviewUrl": "https://www.google.com/maps/reviews/data=!4m8!14m7!1m6!2m5!1sCi9DQUlRQUNvZENodHljRjlvT2xWdVUzTXlTbUY0U1hwSFF6SkNNbWx2YW1sdFZrRRAB...","stars": 4,"text": "Great service and experience. I wish the menu was less focused on sea food and a bit more variety. Recommended.","textLanguage": "en","publishedAtDate": "2026-07-06T09:19:28.897Z","publishedAtText": "2 months ago","daysSincePublished": 88,"likesCount": 0,"reviewerName": "Raph","reviewerIsLocalGuide": false,"reviewerReviewsCount": null,"reviewerProfileUrl": null,"ownerReplied": true,"ownerReplyText": "Thanks so much for your kind words! We're delighted you had a great experience with us. We also appreciate your feedback about the menu; we'll certainly pass on to our team for consideration.","ownerReplyPublishedAtDate": "2026-08-03T09:58:34.381Z","replyLatencyDays": 28,"sentiment": "positive","sentimentScore": 0.45,"sentimentMethod": "stars+lexicon","needsResponse": false,"scrapedAt": "2026-10-02T09:58:34.381Z"}
ownerReplyPublishedAtDate and replyLatencyDays are derived from Google's relative label for the reply ("2 weeks ago" etc.) — Google exposes no exact timestamp for owner replies. The error grows with the reply's age, and both fields are null when the label can't be resolved to a date at or after the review itself.
(This row is the first row of test/production-sample.json, a real recorded run committed in the repo, and is shown verbatim — reviewerName is the public display name exactly as Google Maps shows it, here a single-word handle. The same file proves ownerReplied/ownerReplyText/ownerReplyPublishedAtDate/replyLatencyDays end-to-end: 46 of its 61 rows have ownerReplied: true, and on a 60-review sample from the same place replyLatencyDays resolved for 22/22 answered reviews — see owner_reply_detection in TEST_REPORT.json.)
A skip row for an invalid URL or a place with zero public reviews looks like this instead (never billed, taken verbatim from test/production-sample.json):
{"placeUrl": "https://example.com/not-a-google-maps-url","placeId": null,"skipped": true,"skipReason": "not a Google Maps place URL","scrapedAt": "2026-10-02T09:58:31.146Z"}
How to use via API
curl
curl "https://api.apify.com/v2/acts/YOUR_USERNAME~google-maps-reviews-reputation-tracker/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \-H "Content-Type: application/json" \-d '{"placeUrls": ["https://www.google.com/maps/place/?q=place_id:ChIJN1t_tDeuEmsRUsoyG83frY4"],"maxReviewsPerPlace": 50,"maxResults": 200,"onlyUnanswered": true,"maxStars": 3}'
JavaScript (apify-client)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });const run = await client.actor('YOUR_USERNAME/google-maps-reviews-reputation-tracker').call({placeUrls: ['https://www.google.com/maps/place/?q=place_id:ChIJN1t_tDeuEmsRUsoyG83frY4'],maxReviewsPerPlace: 50,maxResults: 200,onlyUnanswered: true,maxStars: 3,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Python (apify-client)
from apify_client import ApifyClientclient = ApifyClient("YOUR_API_TOKEN")run_input = {"placeUrls": ["https://www.google.com/maps/place/?q=place_id:ChIJN1t_tDeuEmsRUsoyG83frY4"],"maxReviewsPerPlace": 50,"maxResults": 200,"onlyUnanswered": True,"maxStars": 3,}run = client.actor("YOUR_USERNAME/google-maps-reviews-reputation-tracker").call(run_input=run_input)for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item)
Pricing
Pay-per-result (PAY_PER_EVENT), billed as one Result event per review actually pushed to the dataset. Reviews removed by your own filters (onlyUnanswered, minStars/maxStars, reviewsNewerThan, invalid/empty places) are never charged.
| Tier | Price per 1,000 reviews |
|---|---|
| Free | $0.27 |
| Bronze | $0.23 |
| Silver | $0.21 |
| Gold | $0.18 |
| Platinum | $0.18 |
| Diamond | $0.18 |
This undercuts the niche leader (compass/Google-Maps-Reviews-Scraper, $0.30/1000 Gold) while adding sentiment, reply latency and the needsResponse triage flag at no extra cost.
Legal & privacy
This Actor only reads what Google Maps already shows to any anonymous visitor on a public place page — no login, no paywall, no access-control bypass, no CAPTCHA-solving. Reviewer names are personal data under GDPR even when publicly displayed; by default the Actor does not fetch the reviewer's profile URL or contribution count (includeReviewerProfile=false), performs no enrichment, and does no cross-source identity resolution. You, the Apify user running this Actor, are the data controller for any dataset you export — please handle it under your own GDPR obligations. Google's Maps terms discourage bulk download/caching of Maps content; this is a contractual risk for the party scraping, not a technical access-control violation (no account is used or at risk here), and the practice is widely operated on Apify. Decide knowingly.
Troubleshooting
- Empty or very few results for a place: the place may have fewer reviews than
maxReviewsPerPlace, or your filters (minStars/maxStars/onlyUnanswered/reviewsNewerThan) excluded the rest. Check the dataset for askipped: truerow with askipReason, or the run log. - A place/URL never appears in the output: look for its
skipped: truerow —skipReasonexplains why (invalid URL, zero public reviews, a fetch error, or all reviews removed by your own filters); skip rows are never billed. - Repeated HTTP 429 / "unusual traffic": switch
proxyConfigurationfrom datacenter to residential proxy groups; Google is rate-limiting the datacenter IP range for that place. replyLatencyDaysisnulleven thoughownerRepliedistrue: either the owner reply's relative label (Google gives no exact timestamp for replies, see below) couldn't be parsed, or it resolved to a date before the review itself — too coarse to place reliably, so the Actor drops it tonullinstead of publishing an impossible date pair.- Non-English reviews show
sentimentMethod: "stars"instead of"stars+lexicon": the sentiment lexicon only covers common English words; other languages fall back to the star-anchored method, which is still returned, just less text-aware. - Log line
reviewsSort="newest" came back empty; fell back to sort="relevant": for a small number of places Google's ownnewest-sorted endpoint returns nothing even though the place has reviews; the Actor retries once withrelevantso you still get results instead of an empty place. Results for that place are not ordered the way you requested, butreviewsNewerThanis still applied correctly per review (no reviews are silently dropped by the pagination cutoff).
FAQ
Does this use the official Google Places API? No. The Places API caps review results at roughly 5 per place, which isn't enough for reputation monitoring. This Actor reads the same public review data Google serves to the Maps website.
Is the sentiment analysis AI-based?
No — it's a transparent, rule-based method anchored on the star rating with an English lexicon fallback (sentimentMethod tells you which rule produced the label). This keeps the Actor fast and free of per-review API cost. Disable it with computeSentiment=false for a pure raw dump.
Can I monitor the same places on a schedule?
Yes — combine reviewsSort=newest with reviewsNewerThan (e.g. "7 days") on an Apify Schedule to pull only new reviews each run and keep cost low.
Will I be charged for reviews filtered out by onlyUnanswered or star filters?
No — filtering happens before the row is pushed to the dataset, and billing only happens on pushed rows.
How many reviews per place can I get?
Up to 60 newest reviews per place per run — Google's review-list response caps out at 60 regardless of the requested page size, and the pagination token it returns consistently comes back empty over plain HTTP. This Actor is built for recurring monitoring (schedule + reviewsNewerThan) rather than a one-time full historical backfill of a place with thousands of reviews.
What happens to an invalid place URL or a place with zero reviews?
It gets a structured skip row (skipped: true, skipReason explaining why) instead of failing the run or being silently dropped, and it is never billed.
Keywords
google maps reviews scraper, google reviews sentiment analysis, google maps reputation tracker, review response tracker, unanswered google reviews, owner reply latency, google reviews api alternative, local seo review monitoring, multi location review export, google business profile reviews export, review sentiment csv export, scrape google reviews without api key
Hashtags
#GoogleMaps #GoogleReviews #ReviewScraper #ReputationManagement #LocalSEO #SentimentAnalysis #LeadGeneration #WebScraping #Apify #CustomerFeedback #MultiLocation