Review Monitor: Negative Review Alerts and Rating Drift avatar

Review Monitor: Negative Review Alerts and Rating Drift

Pricing

from $12.00 / 1,000 entity checkeds

Go to Apify Store
Review Monitor: Negative Review Alerts and Rating Drift

Review Monitor: Negative Review Alerts and Rating Drift

New 1-2★ reviews, rating drift, owner-reply rate and review velocity per watched business, app or SaaS product since your last run; $12 per 1,000 checks. Alerts $2 per 1,000. 11 sources incl. Booking, Tripadvisor, Google Maps, Yelp, app stores, Capterra. No reviewer names.

Pricing

from $12.00 / 1,000 entity checkeds

Rating

0.0

(0)

Developer

Arcadium Data

Arcadium Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

Review Monitor: New Negative Reviews and Rating Drift

Give it a watchlist of hotels, restaurants and local businesses, apps or SaaS products (their page URLs on Booking.com, Agoda, Trip.com, Tripadvisor, Google Maps, Google Hotels, Yelp, Google Play, the App Store, Capterra or TrustRadius) and every run tells you what changed since the last run. You get one alert row for each new 1★ or 2★ review and one summary row per entity with rating drift, the 30-day average against the lifetime average, owner-reply rate and reply lag, review velocity and, for apps, a per-version rating regression.

All sources come back in one feed with one row shape, deduplicated, with no reviewer names or avatars. Schedule it daily and connect a webhook, Slack or a sheet through Apify integrations.

It is for hotel groups and franchises watching many locations, agencies reporting on clients' reputation, app teams who need to know when a release hurts the rating, and product marketers tracking their SaaS product next to competitors.

Use with AI agents

Returns new negative reviews and reputation metrics (rating drift, 30-day vs lifetime average, owner-reply rate and lag, velocity, app-version regressions) per watched URL since the previous run. Agents can call it through the Apify MCP server (https://mcp.apify.com, open source as apify/actors-mcp-server) as arcadium/reputation-monitor: the input schema is read from the actor, the result is a dataset of JSON rows.

Input example (minimal):

{
"startUrls": [
"https://www.booking.com/hotel/gb/the-savoy.html",
"https://www.yelp.com/biz/katzs-delicatessen-new-york",
"https://apps.apple.com/us/app/slack/id618783545"
],
"stateKey": "my-watchlist"
}

What comes back: one summary row per entity and one alert row per new review rated at or below alertMaxRating (default 2) since the last run with the same stateKey. Filter on the rowType field; flags on the summary row lists what needs attention (new_negative, rating_drop, recent_below_lifetime, version_regression, unanswered_negative, velocity_spike). The first run per entity is a baseline: it records the newest reviews as history and returns only the summary (status: "baseline") at the cheaper baseline price; alerts start with the second run. A URL that fails gets a free error row with a code (invalid_input, not_found, blocked, unavailable or no_match), a message and the input. Retry on blocked and unavailable later; do not retry the other codes with the same input.

Cost of a daily check of 100 entities with 3 new negative reviews in total: 100 checks at $12 per 1,000 plus 3 alerts at $2 per 1,000 is about $1.21 per run on the free plan. The first run of the same list costs about $0.90 (baseline). Error rows are never charged.

What you get

Summary row, one per entity and run:

FieldWhat it holds
statusbaseline (first run), changed (new or edited reviews) or unchanged.
rating, previousRating, ratingChangeThe source's average now, at the previous run, and the drift in stars.
reviewCount, reviewCountChangeStated review count (app stores: star ratings) and how much it grew.
newReviews, newNegativeReviews, newReviewsAvgRatingReviews first seen this run, how many became alerts, and their average.
avgRating30d, avgRatingLifetime, rating30dVsLifetimeRecent vs usual. Negative = recent reviews are worse.
reviews7d, reviews30d, reviewsPrior30d, reviewsPerWeekVelocity.
ownerReplyRate90d, medianReplyLagDays, unansweredNegative30dReply rate of the last 90 days, median days to reply, negative reviews still without a reply.
appVersions, versionRegressionApps: rating per version, and the newest version when it averages 0.5+ stars below the one before.
windowComplete30dtrue when the remembered history reaches back 30 days, so the 30-day figures are exact.
flagsWhat needs attention (empty on a baseline).

Output example:

{
"rowType": "summary",
"status": "changed",
"platform": "appstore",
"entityId": "618783545-us",
"input": "https://apps.apple.com/us/app/slack/id618783545",
"name": "Slack",
"url": "https://apps.apple.com/us/app/slack/id618783545",
"checkedAt": "2026-10-21T22:59:28.653Z",
"previousCheckAt": "2026-10-21T22:54:50.343Z",
"rating": 4.14,
"previousRating": 4.14,
"ratingChange": 0,
"reviewCount": 54143,
"previousReviewCount": 54115,
"reviewCountChange": 28,
"newReviews": 6,
"editedReviews": 0,
"newNegativeReviews": 1,
"newReviewsAvgRating": 4.5,
"avgRating30d": 3.29,
"previousAvgRating30d": 3.29,
"reviews7d": 55,
"reviews30d": 100,
"reviewsPerWeek": 23.3,
"avgRatingLifetime": 3.29,
"lifetimeSource": "sample",
"rating30dVsLifetime": 0,
"ownerReplyRate90d": 0.05,
"medianReplyLagDays": 0,
"unansweredNegative30d": 35,
"appVersions": [],
"versionRegression": null,
"windowComplete30d": false,
"historyReviews": 100,
"historySince": "2026-10-08",
"stopReason": "onlyNew",
"flags": ["new_negative", "unanswered_negative"]
}

Alert row, one per new negative review:

{
"rowType": "alert",
"platform": "appstore",
"entityId": "618783545-us",
"entityName": "Slack",
"entityUrl": "https://apps.apple.com/us/app/slack/id618783545",
"reviewId": "AppStore___14688767912",
"date": "2026-10-20",
"rating": 2,
"title": "Issue",
"text": "A lot of issues when bringing up certain things they don't bring them up in order unless you put that you want newest. ...",
"appVersion": null,
"ownerReplied": true,
"ownerReply": "Ah, apologies, we're working to tackle this bug. ...",
"changeType": "new",
"checkedAt": "2026-10-21T22:59:28.653Z"
}

changeType: "edited" marks a review you already knew that its author edited down into the alert band.

Input

FieldWhat it does
startUrlsOne URL per entity: Booking.com, Agoda or Trip.com hotel, Tripadvisor hotel/restaurant/attraction, Google Hotels hotel, Google Maps place (restaurant, shop, clinic, any business), Yelp business, Google Play app, App Store app, Capterra product, TrustRadius product. Up to 2,000.
stateKeyNames the watchlist. Each run is compared with the last run of the same name. A new name starts a new baseline.
alertMaxRatingAlert at or below this many stars (1-4, default 2). Booking, Agoda, Trip.com and TrustRadius 1-10 scores are halved first.
maxReviewsPerEntityNewest reviews read per entity and run, default 100. Later runs stop at the last review seen, usually after one page.
language, countryGoogle Play review language (default en) and app store country (default us).
includeErrorRowsFree error rows, on by default.

How the comparison works

The actor keeps two small records per entity and watchlist in your account: the ids of the reviews it has seen (reputation-monitor-seen) and a history of review facts (date, rating, replied, reply date, app version; no text) in reputation-monitor-state. Each run reads the newest reviews until it reaches ones it has seen, writes the rows and saves the new state.

  • The first run per entity and watchlist only records the history: no alerts, cheaper price.
  • A reply that arrives days after the review is picked up on the next run that still reads that review (the run re-reads the last 7 days).
  • If a run stops early (your maximum cost per run), the reviews that were not alerted stay unseen and come with the next run.
  • The same entity under two URLs is checked once, and each review is reported once.

Alerts: webhook, Slack, sheets

Use Apify's own integrations on a schedule: add a webhook for "Run succeeded" that posts the dataset link to your endpoint, or use the Slack, Google Sheets, Zapier or Make integrations. Filter on rowType: "alert", or on summary rows whose flags are not empty.

Use it from an AI assistant

Use the Apify actor "arcadium/reputation-monitor" to watch these places and apps.
Input: {"startUrls":["https://www.booking.com/hotel/gb/the-savoy.html","https://www.yelp.com/biz/katzs-delicatessen-new-york"],"stateKey":"daily"}
Rows with rowType "alert" are new 1-2 star reviews. Rows with rowType "summary" have rating, ratingChange,
avgRating30d, ownerReplyRate90d and flags per entity. The first run is a baseline with no alerts.
Run it, then summarise what went wrong in the new negative reviews and which entity needs a reply first.

Use it from code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("arcadium/reputation-monitor").call(run_input={
"startUrls": ["https://www.booking.com/hotel/gb/the-savoy.html"],
"stateKey": "daily",
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if row["rowType"] == "alert":
print(row["entityName"], row["rating"], row["text"][:80])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('arcadium/reputation-monitor').call({
startUrls: ['https://apps.apple.com/us/app/slack/id618783545'],
stateKey: 'daily',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.rowType === 'summary' && i.flags.length > 0));

Pricing

You pay per entity checked and per alert row, at the price of your Apify plan. The first run per entity is a cheaper baseline. Error rows are free.

Apify planPer 1,000 entity checksPer 1,000 alertsPer 1,000 baselines
Free$12.00$2.00$9.00
Starter (Bronze)$12.00$2.00$9.00
Scale (Silver)$12.00$2.00$9.00
Business (Gold)$12.00$2.00$9.00
Platinum$12.00$2.00$9.00
Diamond$12.00$2.00$9.00

Plus a one-off $0.001 per GB of memory when a run starts.

Examples: one hotel checked daily for a month is 30 checks, $0.36 plus a few cents of alerts. 50 locations checked daily is about $18 a month. Set a maximum cost per run in the Apify run options and the actor stops before it goes over.

Use cases

  • Hotel groups and franchises: one feed for every location on Booking, Tripadvisor and Yelp; reply to the new 1★ reviews first, watch ownerReplyRate90d per location.
  • Agencies: a weekly reputation report per client from the summary rows (ratingChange, rating30dVsLifetime, reviewCountChange).
  • App teams: versionRegression shows when a release averages clearly lower than the one before it; alerts carry the appVersion.
  • SaaS product marketing: watch your Capterra and TrustRadius pages and three competitors' in one watchlist.

Limitations

  • Public review pages only. Nothing behind a login.
  • Supported: Booking.com, Agoda and Trip.com hotels (Agoda: its own reviews, not the Booking.com ones it also shows), Tripadvisor places, Google Hotels hotels and Google Maps places (Google's own reviews; dates are approximate because Google shows "3 months ago"), Yelp businesses, Google Play and App Store apps, Capterra and TrustRadius products. Other URLs return a free invalid_input error row.
  • The 30-day, reply and velocity figures come from the reviews the actor has read. For entities with more reviews per month than maxReviewsPerEntity they describe the newest reviews read (windowComplete30d: false) until the history fills up over later runs.
  • App stores state the average of all star ratings, most of them without text, so avgRatingLifetime there is the average of the written reviews read (lifetimeSource: "sample").
  • Reply lag needs a reply date: Tripadvisor, Agoda, Trip.com, Yelp and the app stores have one; Booking and Capterra show the reply only; TrustRadius has no owner replies.
  • App versions: Google Play states the version on every review. The App Store does so only on its RSS feed, which the actor uses as a fallback, so App Store version data is usually empty.
  • TrustRadius is read through residential proxies; the actor reads at most 3 pages (30 reviews) per TrustRadius product and run.
  • A review that is deleted on the site is not reported.
  • Entities are read one after another, about 5 seconds each (7 on the first run), so 700 entities take about an hour. The default run timeout is 4 hours; split bigger watchlists into several stateKeys run in parallel.

Privacy

Reviewer names, avatars, profile links and similar fields are never collected. Email addresses and phone numbers inside review text are replaced by [email] and [phone], and names in greetings ("Dear John") are removed. The saved history holds only review ids, dates, ratings, reply status and app versions.

FAQ

Why did the first run return no alerts? It is the baseline: there is nothing to compare with yet. It records the newest reviews per entity and returns one summary row each at the baseline price. Run it again tomorrow (or put it on a schedule) and the alerts come.

How do I start over? Use a new stateKey. The old records stay in the reputation-monitor-state and reputation-monitor-seen stores until you delete them.

Can I get every new review, not only the negative ones? Set alertMaxRating to 4 for everything below 5 stars, or use the per-site review actors with "only new reviews" for full review rows.

Something looks wrong in the output. Who do I tell? Open an issue on the actor page with the run link. We read them all.