ScavioScavio
ToolsPricing
Sign InsGet Startedg
Blog
google-mapsreviewslead-genlocal-seogoogle-reviews-api

How to Find Businesses With Recent Bad Google Reviews

Sort by lowest rating, one page per business, then filter on last-edit date. That found all 46 Phoenix profiles carrying a recent 1-star, for 60 credits.

August 29, 2026
9 min read
Try Scavio FreePricing

50 free credits · no credit card

Sort by lowest rating, take one page per business, then filter on the review's last-edit date rather than its posted date. Across 60 Phoenix business profiles pulled through Scavio's /api/v2/google/maps/reviews, sort_by=lowest_rating found every profile carrying a 1- or 2-star review from the last six months, 46 of 46, at one page and one credit each. sort_by=newest found 70% of them and would have cost roughly fourteen times more to close the gap.

That is the whole method. The rest of this post is why the two obvious alternatives fail, and the one field that quietly ruins the result if you read the wrong one.

No Google reviews API filters by star rating

This is the constraint everything else follows from. Every reviews endpoint on the market gives you a sort, not a filter. Scavio's /api/v2/google/maps/reviews accepts sort_by of relevance, newest, highest_rating or lowest_rating, and no rating or date parameter at all. SerpApi's published parameter list for the same job is data_id, place_id, hl, sort_by, topic_id, query, num and next_page_token, with sort values qualityScore, newestFirst, ratingHigh and ratingLow. Same shape, same gap.

The consequence is that "businesses with a 1-star in the last six months" cannot be expressed as a query. You pull reviews and you filter them yourself, and the only decision that is actually yours is which sort you pay for. That decision turns out to matter a lot.

The trap in the tooling built on top is worth knowing too: the wrappers that do expose a date cutoff generally implement it by forcing the sort to newest. So the one control that sounds like it solves this problem takes away the sort that does.

What we measured

Four local-service verticals in one metro, because these are the verticals reputation and lead-gen work actually targets: auto repair, dentist, HVAC contractor, moving company. Top 15 results each from /api/v2/google/maps/search with map center @33.4484,-112.0740,12z, giving 60 distinct business profiles with a median of 578 lifetime reviews.

For each profile we pulled one page of 20 reviews two ways, sort_by=lowest_rating and sort_by=newest. That is 2,280 review objects for 124 credits, or $1.24, captured 2026-08-28. A profile counts as qualified if it carries at least one 1- or 2-star review inside 183 days.

Bash
curl -X POST https://api.scavio.dev/api/v2/google/maps/reviews \
  -H "Authorization: Bearer $SCAVIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data_id":"0x872b1268adc9c6a5:0x3d84be39dcfdfa4","sort_by":"lowest_rating","num":20}'

Lowest rating wins on recall and on cost at the same time

The result that surprised us: the cheap method is also the complete one.

sort_by=lowest_ratingsort_by=newest
Qualified profiles found46 of 46 (100%)32 of 46 (70%)
Pages fetched6060
Median history on page 1all-time68 days
Page 1 covers a full 183 daysalways12 of 60 profiles
Pages to cover 183 days13 median, 183 worst case
Estimated credits for the window60about 824

newest is expensive for a reason that is easy to miss when you reason about it instead of measuring it. A page of 20 newest reviews spans a median of 68 days, and only 12 of the 60 profiles had a first page that reached back a full six months on its own. To actually cover the window on the newest sort you paginate until the dates fall off the end, and on the busiest profile in the sample, an HVAC contractor with 34,803 lifetime reviews whose 20 newest reviews spanned a single calendar day, that is a floor of roughly 180 pages for one business. Sorting by lowest rating puts every bad review this business has ever received on page 1 by construction.

The recall gap is the same effect seen from the other side. newest missed 14 qualified profiles not because their bad reviews were old, but because their good reviews were numerous enough to push the bad ones off page 1.

But 72% of what comes back is stale

Recall is not the same as an answer. Page 1 of the lowest-rating sort is sorted by rating, and nothing else, so what you get is a business's worst reviews across its entire history.

Age distribution of the reviews returned on page 1 of the lowest-rating sort, showing 72 percent falling outside a six-month window

Median age 1.4 years. The oldest review returned as a current result was 14.6 years old. So the sort buys you completeness for one credit and hands you the date filter as homework, which is fine, as long as you know the filter is not optional. A list built by taking the lowest-rating page at face value is a list of businesses that had a bad month in 2019.

Two of the 60 profiles returned a page of nothing but 5-star reviews. That is not an error and it is the single cleanest signal in the dataset: an ascending sort that opens at five stars means the profile has no low reviews at all. Those are the two businesses to drop first.

The field that ruins the filter

Google's review objects carry two timestamps and they are not interchangeable.

  • iso_date is when the review was posted.
  • iso_date_of_last_edit is when it was last changed, and it is the key the newest sort orders by, and it is what the human-readable date string reflects.

Here is a real 1-star review from an HVAC contractor in the sample:

JSON
{
  "rating": 1,
  "date": "Edited a day ago",
  "iso_date": "2020-08-06T22:30:12Z",
  "iso_date_of_last_edit": "2026-08-27T18:25:24Z"
}

Filter that on iso_date and you discard it as a six-year-old complaint. Google displays it as a day old. A customer who came back after six years to sharpen a 1-star review is not stale intent, and the profile owner is looking at it right now.

This is not an edge case. 15.8% of the 2,280 reviews we captured carried a last edit at least a day after posting, with a median gap of 389 days and a longest of 12.1 years. Within the sample, 23 low-star reviews sit inside the six-month window by last-edit date and outside it by posted date, and one of the 46 qualified profiles is only visible at all if you read the edit field. Read iso_date_of_last_edit, and fall back to iso_date when it is absent.

Serial one-star reviewers are real, and smaller than you think

The standard objection to any list built this way is that a meaningful share of 1-stars come from accounts that leave 1-stars everywhere, so the business is not a lead, the reviewer is just a reviewer. The reviews carry enough identity to test that: each one has a user.link, a user.name and a user.reviews lifetime count.

Across the 60 profiles there were 891 distinct low-star reviewer identities, and 57 of them, 6.4%, appeared on more than one of the 60. Median lifetime review count was 8 for authors of 1- and 2-star reviews against 5 for authors of 5-star reviews. So the effect is real, it is worth a dedup pass keyed on user.link once your own crawl is large enough for repeats to show up, and it is nowhere near the dominant source of noise. Staleness is, by roughly an order of magnitude.

Where this breaks

One metro, four verticals, 60 profiles, page 1 only. The 100% recall figure is measured against qualified profiles as identified by either method on page 1, so it is a statement about which sort surfaces more, not a proof that a lowest-rating first page is exhaustive for a business with thousands of 1-stars. Deleted reviews are gone from both sorts, so neither method reconstructs history. And the 6.4% repeat-reviewer rate is only within these 60 profiles; the true rate across a metro is higher and you will only see it once you have crawled enough of one.

Worth flagging separately: one of the SERPs we pulled while researching this returned an organic result at position 3 as a raw google.com/goto token rather than a destination URL. When we measured the goto rollout yesterday, every organic token in that capture sat at position 1 or 2, so this one falls outside the band we had observed. If you are joining review data back to organic positions, resolve those tokens before you store them.

The recipe

Three calls and a filter.

  1. /api/v2/google/maps/search with your vertical and an ll map center, for the data_id of each business. 1 credit per 20 results.
  2. /api/v2/google/maps/reviews per business with sort_by=lowest_rating and num=20. 1 credit each.
  3. Keep reviews where rating <= 2 and iso_date_of_last_edit is inside your window. Drop profiles whose page opens at 5 stars.
  4. Dedup on user.link across your whole crawl, not per business.

At 500 businesses that is 25 search calls plus 500 review calls, so 525 credits, $5.25 for a metro-wide pass. Re-running it weekly to catch new complaints is another $5.25 a week, because reviews you already have do not need to be fetched twice.

FAQ

How do I see the 1-star reviews on a Google Business Profile?

In the Maps interface you sort the reviews panel by lowest rating. Programmatically it is the same operation: Scavio's /api/v2/google/maps/reviews with sort_by=lowest_rating returns them worst-first, 20 per page, for 1 credit. There is no parameter that returns only 1-stars, so you filter on rating in your own code.

How do I extract Google reviews to a spreadsheet?

Call the reviews endpoint per business and flatten the reviews array. The fields worth keeping are rating, iso_date_of_last_edit, snippet, user.name, user.link and user.reviews. place_info on the same response carries the business title, address, rating and lifetime reviews count, so one call gives you both the row and its parent record.

Can I filter Google reviews by date range through an API?

No public Google reviews API exposes a date filter, and neither does any of the third-party endpoints we checked. You get sort order and pagination. The practical approach is to sort by lowest rating, which is bounded at one page per business, and apply your date window client-side rather than sorting by newest and paginating until the dates run out.

Why do some reviews show a date that does not match iso_date?

Because the display string tracks edits. A review posted in 2020 and edited yesterday reads "Edited a day ago" while iso_date still says 2020. Use iso_date_of_last_edit for anything recency-based, and treat iso_date as the creation timestamp it is.

Is scraping Google reviews legal?

Reading public review data through a search API is a different act from scraping logged-in surfaces or circumventing access controls, and it is the route we build on. The review text is still the author's, and republishing it verbatim carries its own obligations separate from how you obtained it. Our longer treatment is in Google Reviews API: legal considerations and alternatives.

Can a business get rid of a bad Google review?

Only by reporting it against Google's content policies or persuading the author to remove it, and neither is reliable. That unreliability is exactly why recent negative reviews are a usable outreach signal: the owner cannot make it go away, so the problem is still theirs when you call.

What this leaves you owning

You now own a weekly job that resolves 500 data_id values, pulls a review page for each, tracks which complaints you have already seen so a re-run does not re-alert on a two-month-old 1-star, and reads the correct one of two nearly identical date fields. When Google changes a response shape, or the review panel starts paginating differently, that job breaks quietly and your lead list simply gets shorter, which is the failure mode nobody notices for a month.

Scavio absorbs the part that changes. Proxy rotation, the map-center handling that decides which businesses you even see, and normalizing Google's review objects into the same shape run on our side, so a layout change upstream is our on-call rather than your Monday. What stays yours is the filter, which is four lines and does not rot.

Pricing is 1 credit per call, $0.01 per credit, no monthly commitment. The metro-wide pass above is $5.25. The 60-profile run behind every number in this post cost $1.24.

Start with 50 free credits, no card required — enough to run one vertical in one city and check the 72% staleness figure against your own market before you spend anything.

Endpoint reference: Place Reviews and Maps Search.

Continue reading

google-serp-apiai-overview

How to Get Real URLs From Google AI Overview Citations

8 min read
google-serp-apigoogle-maps-api

How to Get More Than 10 Results From a Google Search API

9 min read
ScavioScavio

One scraper API for every social, search and ecommerce platform. Built for AI agents.

Product

  • Features
  • Pricing
  • Dashboard
  • Affiliates

Developers

  • Documentation
  • API Reference
  • Quickstart
  • MCP Integration
  • Python SDK

Alternatives

  • Tavily Alternative
  • SerpAPI Alternative
  • Firecrawl Alternative
  • Exa Alternative
  • Serper Alternative
  • Tavily vs Scavio
  • SerpAPI vs Scavio
  • All alternatives
  • Compare Scavio vs alternatives

Search APIs

  • Google Search API
  • Amazon Product API
  • YouTube API
  • Reddit API
  • Walmart Product API
  • TikTok API
  • Instagram API

Tools

  • All Tools

© 2026 Scavio. All rights reserved.

Featured on TAAFT
Terms of ServicePrivacy Policy