Google Maps Reviews Scraper (Bad Review Finder) avatar

Google Maps Reviews Scraper (Bad Review Finder)

Under maintenance

Pricing

from $2.99 / 1,000 results

Go to Apify Store
Google Maps Reviews Scraper (Bad Review Finder)

Google Maps Reviews Scraper (Bad Review Finder)

Under maintenance

Get clean Google Maps review data for insights. The actor collects comments, star ratings, reviewer info, and timestamps. Ideal for customer experience tracking, trend analysis, and data driven decision making.

Pricing

from $2.99 / 1,000 results

Rating

0.0

(0)

Developer

SimpleAPI

SimpleAPI

Maintained by Community

Actor stats

0

Bookmarked

10

Total users

0

Monthly active users

2 days ago

Last modified

Share

Google Maps Reviews Scraper (Bad Review Finder)

Google Maps Reviews Scraper (Bad Review Finder) reads a place's public Google Maps reviews and returns only the ones worth a reply: the star ratings you choose, with real written text, in the languages your team answers in, optionally limited to reviews with no owner response yet. Every row also carries the place's whole ratingDistribution — a 1-to-5-star count pulled from Google's own histogram — plus negativeReviewShare, text, stars, reviewerNumberOfReviews, and responseFromOwnerText. Built for support teams, reputation-management agencies, and franchise auditors who need a complaint queue, not a full review dump.

What is Google Maps Reviews Scraper (Bad Review Finder)?

It is an Apify Actor that opens a Google Maps place, drives its live reviews feed, and pushes one dataset row per review that survives a complaint filter you configure — star rating, written-text requirement, minimum length, review language, and reply status. No Google account, login, or API key is required: the Actor reads the same public reviews tab a visitor sees. The filter runs inside the scroll loop itself, so maxReviews counts matching reviews and the feed keeps reading (up to maxReviewsScanned) until that many complaints exist or the read budget runs out.

  • Discovery by URL or Place ID — feed it one or more Google Maps place URLs (startUrls) or raw Place IDs (placeIds); both are audited in the same run
  • A pre-charge complaint filterstarRatings, requireWrittenText, minTextLength, reviewLanguages, and onlyWithoutOwnerReply all run before a review is buffered, so you are never charged for a rejected row
  • Place-wide rating contextratingDistribution (the place's full 1★–5★ histogram), negativeReviewCount, and negativeReviewShare ride on every row, computed once per place
  • Full reviewer identityname, reviewerUrl, reviewerPhotoUrl, reviewerNumberOfReviews, isLocalGuide — or blank all five with personalData: false
  • Owner-reply and sub-rating detailresponseFromOwnerText/responseFromOwnerDate, hasOwnerReply, per-aspect reviewDetailedRating (Food/Service/Atmosphere-style scores), and reviewContext chips (Service, Meal type, Price per person, etc.)
  • Standard Apify dataset exports — JSON, CSV, Excel/XLSX, and the Dataset API, with no extra configuration

What data can I extract with Google Maps Reviews Scraper (Bad Review Finder)?

Every row combines the individual review, the reviewer, the place it belongs to, and the run's own filter accounting — all under the exact JSON key names the Actor writes.

FieldExample ValueUse Case
searchString"https://www.google.com/maps/place/Boucherie+Union+Square/..."Trace a row back to the input URL or Place ID that produced it
reviewerId"104827365991822334455"Stable numeric id for joining a reviewer across runs
reviewerUrl"https://www.google.com/maps/contrib/104827365991822334455"Link to the reviewer's Maps contributor profile
name"Priya N."Display name for a review-management dashboard
reviewerNumberOfReviews47Weight a review by how experienced the reviewer is
isLocalGuidetrueFlag reviews from Google's Local Guide program
reviewerPhotoUrl"https://lh3.googleusercontent.com/a-/ALV-...=s1920"Full-resolution avatar for a review-wall UI
text"Waited 40 minutes for a table..."The complaint text itself — what a manager actually reads
textLength127Filter out one-word ratings before triage
publishAt"3 months ago"The exact string Google renders on the card
publishedAtDate"2026-05-01T00:00:00.000Z"Sortable/derived date for trend charts
likesCount4Rank complaints by how many people agreed
reviewId"ChdDSUhNMG9nS0VJQ0FnSURwd2R6cmZ3"Google's own review identifier, for dedup
reviewUrl"https://www.google.com/maps/reviews/data=..."Deep link straight to the review on Maps
stars2The rating the complaint filter matched on
responseFromOwnerDatenullAge of the business's reply, if one exists
responseFromOwnerTextnullThe business's own reply text, if any
hasOwnerReplyfalseBoolean shortcut instead of checking responseFromOwnerText for null
reviewImageUrls["https://lh3.googleusercontent.com/p/AF1..."]Photos the reviewer attached, for a visual audit
reviewContext{"Service": "Dine in", "Meal type": "Dinner"}Google's own context chips for the visit
reviewDetailedRating{"Food": 3, "Service": 1, "Atmosphere": 3}Per-aspect sub-scores, when the reviewer left them
originalLanguage"en"The review's own published language tag
placeId"ChIJc1X1HqFZwokRvupG9K0Xd_I"Google's canonical place identifier
cid"3442553861032018645"Decimal customer id, derived from the place's feature id
fid"0x89c259a1ec5f5573:0x2fc6687f46f682d5"Google's internal feature id, from the Maps URL
location{"lat": 40.7372552, "lng": -73.9882246}Coordinates for mapping or radius work
address"225 Park Ave S, New York, NY 10003"Full mailing address of the place
neighborhood"Union Square"Sub-city area for local segmentation
street"225 Park Ave S"Street line, split out from the full address
city"New York"City-level rollups across a portfolio
postalCode"10003"ZIP/postal-level segmentation
state"NY"State/region rollups
countryCode"US"Two-letter country code
categoryName"French restaurant"Google's primary category label
categories["French restaurant", "Bistro"]Full category list, for niche filtering
title"Boucherie Union Square"The place's display name
totalScore4.7The place's overall published Google rating
reviewsCount5218The place's total published review count
url"https://www.google.com/maps/search/?api=1&query=..."A stable Maps search link back to the place
price"$$"Google's price-range indicator
imageUrl"https://lh3.googleusercontent.com/p/AF1...=w408-h306-k-no"A representative photo of the place
language"en"The Maps interface language actually served for this row
scrapedAt"2026-08-16T14:02:31.118Z"Freshness stamp for dedup/refresh logic
ratingDistribution{"oneStar": 103, "twoStar": 80, "threeStar": 189, "fourStar": 484, "fiveStar": 4362}The place's whole 1-to-5-star mix, the honest denominator
negativeReviewCount183oneStar + twoStar, computed once per place
negativeReviewShare0.0351Negative reviews as a share of the place's total, 0–1
reviewFilterSummary"stars ∈ {1,2} · written text required · text ≥ 40 chars · no owner reply yet"Human-readable record of which filter produced this run
scannedReviewsCount214How many cards were read for this place, matching or not
matchedReviewsCount15How many of those cards survived the filter
droppedByStarsCount172Cards rejected for the wrong (or unreadable) star rating
droppedRatingOnlyCount19Star-only cards rejected for carrying no written text
droppedByLengthCount6Cards rejected for text shorter than minTextLength
droppedByLanguageCount0Cards rejected for a language outside reviewLanguages
droppedByOwnerReplyCount2Cards rejected because the business had already replied
unlabelledLanguageKeptCount0Reviews Google left untagged, kept rather than guessed

📊 Rating context and filter accounting

Every row carries two layers of numbers that are not about the individual review at all. The first is ratingDistribution — the place's full 1★–5★ histogram, read from a deterministic index of the same payload Google's own reviews pane fires, cross-checked against the place's published totalScore before it is trusted. negativeReviewCount and negativeReviewShare are derived from it, so you always know what fraction of the place's whole review history the complaints in this run represent — "183 negative out of 5,218" — without paying to scrape all 5,218. The second layer is the run's own accounting: scannedReviewsCount, matchedReviewsCount, and five droppedBy*Count fields explain exactly why a short result is short, instead of leaving you to guess whether the filter was too strict or the place simply has few complaints.

🗺️ Location and business identity fields

address, neighborhood, street, city, state, postalCode, countryCode, and location (lat/lng) let you group complaint rows by market without a second lookup — useful for rolling a franchise's complaint queue up by region. placeId, fid, and cid are Google's own identifiers for joining rows back to a place across runs, and categoryName/categories/price let you segment a multi-vertical portfolio (restaurants vs. retail vs. services) before triaging complaints.

How does Google Maps Reviews Scraper (Bad Review Finder) differ from the official Google Places API?

Google's own Places API (New) caps how much review data you can pull per place at all, filter-free. Per Google's Place reference: the reviews[] field is "sorted by relevance," and "a maximum of 5 reviews can be returned" per place — there is no parameter to request more, to sort by rating, or to page past the fifth review (Google, Places API (New) reference, checked 2026-08-16).

FeatureGoogle Places API (New) — Place Details reviews fieldGoogle Maps Reviews Scraper (Bad Review Finder)
Reviews returned per placeMaximum 5, sorted by relevance onlyUp to maxReviews matching reviews (max 1,000), found by reading up to maxReviewsScanned cards (max 3,000)
Filter by star ratingNot availablestarRatings keeps only the ratings you pick
Filter by written text / lengthNot availablerequireWrittenText + minTextLength
Filter to unanswered reviews onlyNot availableonlyWithoutOwnerReply
Place-wide 1-to-5-star breakdownOnly an average rating and a userRatingCount total — no per-star countsratingDistribution, negativeReviewCount, negativeReviewShare on every row
Sort orderFixed to relevancereviewsSort: newest, most relevant, highest, or lowest first
SetupGoogle Cloud project, API key, billing enabledApify account only — no Google credentials
Cost basisBilled per request, at the SKU tier your requested fields fall intoBilled per matching review row (row_result)

Why can't I get more than 5 reviews from Google's own API?

Google's Place resource documentation fixes the reviews[] field at five entries per place, sorted by relevance, with no pagination or rating filter (Google, Places API (New) reference, checked 2026-08-16). For a single location that is a minor inconvenience; for auditing a 50-location franchise it means at most 250 reviews total across the whole portfolio, hand-picked by Google's relevance model rather than by star rating — with no way to isolate the one- and two-star complaints inside them. This Actor sidesteps the field entirely: it drives the actual public reviews feed the way a person scrolling the page would, reading review cards straight out of the DOM, so the review count is bounded only by maxReviewsScanned rather than a fixed cap of five.

The official API is the right tool when you already administer the place and only need its aggregate rating/userRatingCount inside your own app. For pulling review-level detail filtered by star rating, text, language, or reply status — across one place or a whole portfolio — that filtering does not exist through the official API today, which is what this Actor is built to cover.

How to use data extracted from Google Maps reviews?

🎧 Customer support and reputation-management teams

Point startUrls at your own location (or a client's), set starRatings to ["1","2"] with onlyWithoutOwnerReply: true, and the run returns exactly the backlog a support lead needs to work through this morning — text, stars, publishAt, and reviewUrl to reply directly. reviewFilterSummary on every row documents which filter produced the queue, so a weekly export is self-explanatory to anyone who opens it.

🏢 Agencies auditing client locations

Run the same starRatings/onlyWithoutOwnerReply combination across every client location in one startUrls list on a schedule, then compare negativeReviewShare and matchedReviewsCount per place in a single dataset export — a recurring benchmarking workflow with no per-location manual pull, and a defensible "here's what changed since last month" report.

🔬 Market research and franchise-performance analysis

Feed in every location in a chain or a competitor set and group rows by city/state alongside ratingDistribution to see whether complaint density clusters by region rather than by individual store, using categoryName to keep verticals separate in a mixed portfolio.

🤖 AI agents and automated pipelines

Because the output is flat, typed JSON with text, stars, reviewDetailedRating, and reviewFilterSummary already resolved, it drops directly into an agent tool call for "summarise this week's unanswered one-star reviews for location X" or a RAG index over a support team's complaint history, with no normalization step first.

🔼 Input sample

No parameter is required — the schema's own startUrls prefill and defaults run a 1★/2★ complaint sweep on their own.

ParameterRequiredTypeDescriptionExample Value
startUrlsNoArray of stringsOne or more Google Maps place URLs. Plain strings and {"url": "..."} objects both work.["https://www.google.com/maps/place/Boucherie+Union+Square/..."]
placeIdsNoArray of stringsRaw Google Place IDs (ChIJ...); each is turned into a Maps URL and audited alongside startUrls.["ChIJc1X1HqFZwokRvupG9K0Xd_I"]
starRatingsNoArray of strings, select (15)Which star ratings count as a complaint. Default ["1", "2"]. Selecting all five turns the star filter off. A card whose star widget could not be read is rejected, never assumed negative.["1", "2"]
requireWrittenTextNoBooleanDrop star-only ratings with no written text. Default true.true
minTextLengthNoInteger (0–2000)Minimum character length for the review text. Default 40. Set 0 to keep any text.40
reviewLanguagesNoArray of stringsKeep only reviews tagged in these language codes. Default [] (all languages). Untagged reviews are kept, never guessed.["en", "es"]
onlyWithoutOwnerReplyNoBooleanKeep only reviews with no business reply yet. Default false.true
maxReviewsNoInteger (1–1000)How many reviews that PASS the filter to keep per place. Default 10.15
maxReviewsScannedNoInteger (1–3000)Hard ceiling on review cards READ per place, matching or not. Default 300. You are not charged for rejected cards.500
reviewsSortNoString, enum: newest, mostRelevant, highestRanking, lowestRankingFeed order Google is read in. Default "newest". lowestRanking puts complaints first and is the cheapest way to fill a 1-2 star queue."lowestRanking"
reviewsStartDateAbsoluteNoString (date)Exact cutoff date (YYYY-MM-DD). Accurate to Google's published relative-age bucket, not the exact day. Default ""."2026-01-01"
reviewsStartDateRelativeNoString, enum: "", "7 days", "1 month", "3 months", "6 months", "1 year", "2 years"Rolling-window cutoff, used only when the absolute date is empty. Default ""."3 months"
languageNoString, enum: en, es, fr, de, it, pt, nl, bn, hi, ar, tr, id, ja, ko, zh-CNInterface language of the Maps pages fetched, applied as hl=<code>&gl=us. Changes publishAt, categories, price. Does NOT filter reviews — use reviewLanguages. Default "en"."en"
personalDataNoBooleanWhen false, name, reviewerId, reviewerUrl, reviewerPhotoUrl, and reviewUrl are emitted as null. Default true.true
proxyNoObject (JSON editor)Optional custom proxy (use_proxy, host, port, username, password). Left as-is, the Actor uses Apify Residential (US) with automatic IP rotation.{"use_proxy": false}
{
"startUrls": ["https://www.google.com/maps/place/Boucherie+Union+Square/@40.7372552,-73.9882246,17z/data=!4m6!3m5!1s0x89c259a1ec5f5573:0x2fc6687f46f682d5!8m2!3d40.7372552!4d-73.9882246!16s%2Fg%2F11hbv5rh0_"],
"starRatings": ["1", "2"],
"requireWrittenText": true,
"minTextLength": 40,
"reviewLanguages": ["en"],
"onlyWithoutOwnerReply": true,
"maxReviews": 15,
"maxReviewsScanned": 500,
"reviewsSort": "lowestRanking",
"language": "en",
"personalData": true
}

Common pitfall: maxReviews caps MATCHING reviews, not cards read — maxReviewsScanned is the real budget on run time and how deep the hunt goes. A run that returns fewer rows than maxReviews is not necessarily broken: check droppedByStarsCount, droppedRatingOnlyCount, droppedByLengthCount, droppedByLanguageCount, and droppedByOwnerReplyCount on any row (or the run log) to see which filter absorbed the rest, then either widen starRatings, lower minTextLength, or raise maxReviewsScanned. Also note reviewsStartDateAbsolute always wins over reviewsStartDateRelative when both are set — the relative window is only used when the absolute date is left empty.

🔽 Output sample

Each matching review is pushed to the dataset the moment it survives the filter — typed, normalized JSON with a consistent schema across places. Export directly from the Apify Console as JSON, CSV, or Excel, or read it back through the Dataset API.

{
"searchString": "https://www.google.com/maps/place/Boucherie+Union+Square/@40.7372552,-73.9882246,17z/data=!4m6!3m5!1s0x89c259a1ec5f5573:0x2fc6687f46f682d5!8m2!3d40.7372552!4d-73.9882246!16s%2Fg%2F11hbv5rh0_",
"reviewerId": "104827365991822334455",
"reviewerUrl": "https://www.google.com/maps/contrib/104827365991822334455",
"name": "Priya N.",
"reviewerNumberOfReviews": 47,
"isLocalGuide": true,
"reviewerPhotoUrl": "https://lh3.googleusercontent.com/a-/ALV-abc123=s1920",
"text": "Waited 40 minutes for a table we'd reserved online, then the order came out wrong twice. Nobody from the front desk apologized.",
"publishAt": "3 months ago",
"publishedAtDate": "2026-05-01T00:00:00.000Z",
"likesCount": 4,
"reviewId": "ChdDSUhNMG9nS0VJQ0FnSURwd2R6cmZ3",
"reviewUrl": "https://www.google.com/maps/reviews/data=!4m6!14m5!1m4!2m3!1sChdDSUhNMG9nS0VJQ0FnSURwd2R6cmZ3!2m1!1s0x0:0x2fc6687f46f682d5?hl=en",
"stars": 2,
"responseFromOwnerDate": null,
"responseFromOwnerText": null,
"reviewImageUrls": ["https://lh3.googleusercontent.com/p/AF1abcXYZ"],
"reviewContext": {"Service": "Dine in", "Meal type": "Dinner"},
"reviewDetailedRating": {"Food": 3, "Service": 1, "Atmosphere": 3},
"originalLanguage": "en",
"placeId": "ChIJc1X1HqFZwokRvupG9K0Xd_I",
"location": {"lat": 40.7372552, "lng": -73.9882246},
"address": "225 Park Ave S, New York, NY 10003",
"neighborhood": "Union Square",
"street": "225 Park Ave S",
"city": "New York",
"postalCode": "10003",
"state": "NY",
"countryCode": "US",
"categoryName": "French restaurant",
"categories": ["French restaurant", "Bistro"],
"title": "Boucherie Union Square",
"totalScore": 4.7,
"reviewsCount": 5218,
"url": "https://www.google.com/maps/search/?api=1&query=Boucherie+Union+Square&query_place_id=ChIJc1X1HqFZwokRvupG9K0Xd_I",
"price": "$$",
"cid": "3442553861032018645",
"fid": "0x89c259a1ec5f5573:0x2fc6687f46f682d5",
"imageUrl": "https://lh3.googleusercontent.com/p/AF1placeXYZ=w408-h306-k-no",
"scrapedAt": "2026-08-16T14:02:31.118Z",
"language": "en",
"textLength": 127,
"hasOwnerReply": false,
"ratingDistribution": {"oneStar": 103, "twoStar": 80, "threeStar": 189, "fourStar": 484, "fiveStar": 4362},
"negativeReviewCount": 183,
"negativeReviewShare": 0.0351,
"reviewFilterSummary": "stars ∈ {1,2} · written text required · text ≥ 40 chars · no owner reply yet",
"scannedReviewsCount": 214,
"matchedReviewsCount": 15,
"unlabelledLanguageKeptCount": 0,
"droppedByStarsCount": 172,
"droppedRatingOnlyCount": 19,
"droppedByLengthCount": 6,
"droppedByLanguageCount": 0,
"droppedByOwnerReplyCount": 2
}

How do you filter and target specific reviews?

This is the core of the Actor: the complaint filter runs on every review card before it is buffered or charged, so maxReviews counts matches, not cards read. Four axes combine to define a "complaint": star rating (starRatings — leave all five selected to disable it, or narrow to ["1","2"]/["1","2","3"]), content quality (requireWrittenText plus minTextLength, so a bare tap on one star doesn't count), language (reviewLanguages, matched against each review's own published language tag — never guessed, and an untagged review is kept rather than dropped), and reply status (onlyWithoutOwnerReply, to isolate the actual open work queue). reviewsSort decides which cards get read first — lowestRanking reads negative reviews before positive ones and is the cheapest way to fill a 1–2★ queue, while newest answers "what came in this week." Volume is controlled by two separate budgets: maxReviews (how many matches you want, up to 1,000) and maxReviewsScanned (how many cards may be read while hunting for them, up to 3,000) — the second is automatically raised if it's set below the first.

{ "starRatings": ["1", "2"], "onlyWithoutOwnerReply": true, "reviewsSort": "lowestRanking", "maxReviews": 20, "maxReviewsScanned": 400 }
{ "starRatings": ["1", "2", "3"], "reviewLanguages": ["en", "es"], "requireWrittenText": true, "minTextLength": 60 }
{ "starRatings": ["1", "2"], "reviewsStartDateRelative": "3 months", "maxReviews": 50, "maxReviewsScanned": 1500 }

▶️ Want to try other Google Maps and directory scrapers?

ScraperWhat it extracts
Google Play Scraper — Country Pricing, IAP Tiers and AvailabilityPer-country Google Play Store pricing, in-app purchase tiers, and storefront availability
2GIS Places Scraper — by Direct 2GIS Links2GIS place records — address, coordinates, hours, ratings, contacts and reviews — from links or IDs
Facebook Reviews Scraper — Headlines, Tags & Reviewer DetailPublic Facebook Page reviews with Facebook's own headline, tags, and resolved reviewer identity
Airbnb Review Scraper — Reviews, Ratings and Listings by LocationAirbnb listings for a city or neighbourhood, screened by review count/rating, with guest reviews
Walmart Reviews Scraper — Ratings, Seller & Variant DetailsWalmart product reviews with the exact reviewed SKU/variant and seller/fulfillment details

How to extract Google Maps review data programmatically

The Actor runs as a standard Apify Actor: start it with one API call, poll or webhook for completion, and read back structured JSON from its dataset.

Python example

from apify_client import ApifyClient
client = ApifyClient("<APIFY_API_TOKEN>")
run = client.actor("<ACTOR_ID>").call(run_input={
"startUrls": ["https://www.google.com/maps/place/Boucherie+Union+Square/..."],
"starRatings": ["1", "2"],
"onlyWithoutOwnerReply": True,
"maxReviews": 20,
})
for review in client.dataset(run["defaultDatasetId"]).iterate_items():
print(review["stars"], review["text"], review["reviewFilterSummary"])

Export to spreadsheets or CRM

Export the dataset as CSV or Excel from the Apify Console, or pull it via the Dataset API. Map text and stars to a ticket-body and priority column, reviewUrl to a "reply on Google" link, and name/reviewerUrl to a contact-name and contact-link field — no nested objects to unpack.

Scraping publicly available Google Maps reviews is generally lawful — this Actor reads only reviews Google has already published on a place's public reviews tab, with no login and no private content accessed. Because most rows include personal data — a reviewer's name, contributor profile link, and avatar photo — GDPR and CCPA considerations apply to how you store and use that data, not to the act of reading a public review. Setting personalData: false removes name, reviewerId, reviewerUrl, and reviewerPhotoUrl from every row if you only need the review content and ratings. You are responsible for having a lawful basis for any storage or downstream use of personal data, and for complying with Google's own Terms of Service for your use case. Consult legal counsel for commercial applications involving bulk storage of personal data.

❓ FAQ

How does the Actor handle a review that's later deleted or edited on Google?

It doesn't retroactively re-check past runs — each run reads the place's live reviews feed at request time. If a review has since been deleted or edited, a fresh run simply returns whatever the feed currently shows; there is no separate "edited" or "deleted" flag on old rows.

Can I get the place's whole rating breakdown along with the complaint reviews?

Yes. ratingDistribution (the place's 1★–5★ histogram) and the derived negativeReviewCount/negativeReviewShare are attached to every row, read from the same payload behind Google's own reviews pane and cross-checked against the place's published totalScore. When that histogram isn't available for a place, all three fields come back null rather than a guessed value.

How accurate is the review date (publishedAtDate)?

Google only publishes a relative age per review — "3 months ago," never a calendar date — so publishedAtDate is derived from that bucket and is accurate to the bucket, not the day. publishAt preserves the exact string Google rendered. The derivation is verified against the English interface (language: "en"); other interface languages carry the same bucket-level accuracy.

How many reviews can I get per run?

Up to maxReviews matching reviews per place (maximum 1,000), found by reading up to maxReviewsScanned cards per place (maximum 3,000). Both are per-place limits, and maxReviewsScanned is raised automatically if you set it below maxReviews — you cannot hunt for more matches than you're allowed to read.

What's the difference between reviewLanguages and language?

language sets the interface language of the Maps pages the Actor fetches (hl=<code>&gl=us) — it changes how publishAt, categories, and price are rendered, but it does not filter which reviews come back. reviewLanguages is the actual content filter, matched against each review's own published language tag. Because Google front-loads a feed with reviews written in the selected interface language, the two interact in practice — set language to match the bulk of what you expect, then use reviewLanguages to narrow further.

Does Google Maps Reviews Scraper (Bad Review Finder) work with Claude, ChatGPT, and AI agent frameworks?

It is not published as an MCP server. It is callable as a standard Apify Actor run through the Apify API from any agent framework or HTTP client — including apify_client in Python or Node — so an agent can trigger a run and read the filtered dataset back as a tool call.

How does it compare to other Google Maps review scrapers?

As observed on their own Apify Store listings (checked 2026-08-16), the Compass and Scrapesmith Google Maps Reviews Scrapers both return individual review data with sort-order controls (newest, highest, lowest rating first), but neither exposes a dedicated star-rating filter, an unanswered-only filter, or a place-wide rating histogram — sorting by "lowest rating" still returns every review, so you pay for and store the positive reviews along with the negative ones. This Actor filters before charging and attaches ratingDistribution/negativeReviewShare to every row.

Can I use this without a Google API key or developer account?

Yes. No Google Cloud project, API key, or developer account is needed — only the Maps place URLs or Place IDs you want audited, entered directly into startUrls or placeIds. The Actor drives the public Maps site itself.

Why did a run return fewer rows than my maxReviews?

Either the place genuinely has fewer complaints than you asked for, or the feed hit maxReviewsScanned before finding enough matches. Every row carries scannedReviewsCount, matchedReviewsCount, and the five droppedBy*Count fields, so you can tell the two apart instead of guessing — and a place that read reviews but matched none is a real, reportable result, not a failed run: nothing is pushed and nothing is charged for it.

Conclusion

Google Maps Reviews Scraper (Bad Review Finder) turns a place's public reviews tab into a pre-filtered complaint queue — the star ratings, written text, languages, and reply status you specify, with the place's whole rating mix attached to every row for context. It suits support teams working an actual reply backlog, agencies benchmarking clients on a schedule, and researchers mapping complaint density across a portfolio. Start a run from the Apify Console or trigger it via the Apify API with your list of Maps URLs or Place IDs to get your first complaint queue.