How to use Review Monitor
Step by step: in the Apify Store, over the API, from JavaScript or Python, in n8n, and from AI agents through MCP or LangChain.
$12.00 per 1,000 entities checked (live Apify price on 2026-10-31).
1. In the Apify Store (no code)
- Open arcadium/reputation-monitor and sign in to Apify (a free account works).
- Fill in the input form. The fields below are the ones the example uses.
- Set a maximum cost per run in the run options if you want a hard cap.
- Start the run. Rows appear in the Output tab as they arrive.
- Export the dataset as JSON, CSV or Excel, or connect an integration.
| Input field | Type | Description |
|---|---|---|
startUrls | array | Example: ["https://www.booking.com/hotel/gb/the-savoy.html", "https://play.google.com/store/apps/details?id=com.Slack"]. One URL per hotel, business, app or product. Sources: Booking.com, Agoda or Trip.com hotel, Tripadvisor place, Google Hotels hotel (google.com/travel/hotels/entity/...), Google Maps place (a place link, maps.app.goo.gl link or maps.google.com/?cid=...), Google Play app, App Store app, Yelp business, Capterra product, TrustRadius product. Max 2,000. Required. |
maxReviewsPerEntity | integer | Example: 100. Newest reviews read per entity and run; the first run uses them as history for the 30-day and reply metrics. Later runs stop at the last seen review, usually after one page. Raise it for apps with hundreds of reviews a day. 10-2,000. Also accepted as maxReviews, maxItemsPerQuery or maxReviewsPerHotel (other review actors; clamped to 10-2,000). Default 100. |
Example input:
{
"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"
],
"maxReviewsPerEntity": 50
}
2. Over the Apify API
The synchronous endpoint runs the actor and returns its rows in one call (for runs up to about five minutes; use the asynchronous run endpoint for longer ones).
curl -X POST "https://api.apify.com/v2/acts/arcadium~reputation-monitor/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"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"],"maxReviewsPerEntity":50}'
3. From JavaScript
// npm install apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/reputation-monitor').call({
"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"
],
"maxReviewsPerEntity": 50
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
4. From Python
# pip install apify-client
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/reputation-monitor").call(run_input={
"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"],
"maxReviewsPerEntity": 50,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
5. In n8n
Paste this node into a workflow (it is a plain HTTP Request node). Create a Header Auth credential with name Authorization and value Bearer <APIFY_TOKEN>; each returned row becomes one item for the next node.
{
"nodes": [
{
"name": "Run arcadium/reputation-monitor",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
0,
0
],
"parameters": {
"method": "POST",
"url": "https://api.apify.com/v2/acts/arcadium~reputation-monitor/run-sync-get-dataset-items",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{\"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\"],\"maxReviewsPerEntity\":50}",
"options": {
"timeout": 300000
}
}
}
],
"connections": {}
}
6. From an AI assistant (MCP)
Add Apify’s MCP server to Claude Desktop, Cursor, VS Code or any MCP client, limited to this actor:
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=arcadium/reputation-monitor",
"headers": {
"Authorization": "Bearer <APIFY_TOKEN>"
}
}
}
}
More on the MCP page.
7. From LangChain
# pip install langchain-apify (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("arcadium/reputation-monitor")
rows = tool.invoke({"run_input": {
"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"],
"maxReviewsPerEntity": 50,
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])
Sample output
One row, from the example in the actor’s README. Long text is shortened and lists are cut to two items.
{
"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"
]
}
| Field | What it holds |
|---|---|
rowType | Kind of row. Filter on this first. 'alert': one new (or newly lowered) review at or below the alert rating (charged). 'summary': one per entity and run with drift, reply and velocity metrics (charged as an entity check, or as a cheaper baseline on the first run). 'error': a URL that could not be read or is not supported; see code and message (free). |
platform | Source: booking, tripadvisor, googleplay, appstore, yelp, capterra or trustradius. |
entityId | Native id of the entity on its source (hotel id, place id, app id, business id, product id). |
input | The URL you entered for this entity. |
checkedAt | ISO timestamp of this run's check. |
entityName | Alert rows: name of the hotel, business, app or product. |
entityUrl | Alert rows: public page of the entity. |
reviewId | Alert rows: stable review id '<Platform>___<native id>'. |
reviewUrl | Alert rows: public link to the review, null when the source has none. |
date | Alert rows: review date (YYYY-MM-DD). |
title | Alert rows: review title, null when the source has none. Personal data is redacted. |
text | Alert rows: review text. Emails, phone numbers and names in greetings are redacted. |
pros | Alert rows: what the reviewer liked (Booking, Capterra, TrustRadius), null elsewhere. |
cons | Alert rows: what the reviewer disliked (Booking, Capterra, TrustRadius), null elsewhere. |
language | Alert rows: review language code when the source states it. |
appVersion | Alert rows: app version the review was written for (app stores), null elsewhere. |
ownerReplied | Alert rows: true when the owner or developer has already replied. |
ownerReply | Alert rows: the owner's reply text (redacted), null when there is none. |
changeType | Alert rows: 'new' = first seen this run; 'edited' = a known review whose rating was edited down into the alert band. |
status | Summary rows: 'baseline' (first run, history recorded, no alerts), 'changed' (new or edited reviews) or 'unchanged'. |
name | Summary rows: name of the hotel, business, app or product. |
url | Summary rows: public page of the entity. |
previousCheckAt | Summary rows: ISO timestamp of the previous run with this watchlist name, null on a baseline. |
rating | Rating on 1-5 (Booking and TrustRadius 1-10 scores are halved) as the source states it now. Alert rows: the review's rating. |
previousRating | Summary rows: the source's average rating at the previous run. |
ratingChange | Summary rows: rating minus previousRating (stars). Negative = the average went down. |
reviewCount | Summary rows: review count the source states (app stores: the number of star ratings). |
previousReviewCount | Summary rows: reviewCount at the previous run. |
reviewCountChange | Summary rows: reviewCount minus previousReviewCount, the true number of new reviews/ratings even beyond the read limit. |
newReviews | Summary rows: reviews first seen this run (0 on a baseline). |
editedReviews | Summary rows: known reviews whose text or rating changed since they were seen. |
newNegativeReviews | Summary rows: alert rows written for this entity this run. |
newReviewsAvgRating | Summary rows: average rating of this run's new and edited reviews, null when there are none. |
avgRating30d | Summary rows: average rating of the reviews dated in the last 30 days (from the remembered history). |
previousAvgRating30d | Summary rows: avgRating30d at the previous run. |
reviews7d | Summary rows: reviews dated in the last 7 days. |
reviews30d | Summary rows: reviews dated in the last 30 days (a lower bound when windowComplete30d is false). |
reviewsPrior30d | Summary rows: reviews dated 31-60 days ago, to compare velocity. |
reviewsPerWeek | Summary rows: review velocity, reviews30d per week. |
avgRatingLifetime | Summary rows: lifetime average: the source's stated rating, or for app stores (whose rating counts silent star ratings) the average of the remembered written reviews. |
lifetimeSource | Summary rows: 'site' (the source's stated average) or 'sample' (average of the remembered reviews). |
rating30dVsLifetime | Summary rows: avgRating30d minus avgRatingLifetime. Negative = recent reviews are worse than usual. |
ownerReplyRate90d | Summary rows: share (0-1) of the last 90 days' reviews with an owner reply; null on TrustRadius (no replies). |
replySample90d | Summary rows: number of reviews ownerReplyRate90d is based on. |
medianReplyLagDays | Summary rows: median days from review to owner reply (Tripadvisor, Yelp, app stores); null where the source does not date replies. |
replyLagSample | Summary rows: number of replies medianReplyLagDays is based on. |
unansweredNegative30d | Summary rows: reviews of the last 30 days at or below the alert rating without an owner reply. |
appVersions | Summary rows (apps): up to 5 newest versions in the history: [{ version, reviews, avgRating, firstSeen }]. |
versionRegression | Summary rows (apps): { version, avgRating, reviews, previousVersion, previousAvgRating, previousReviews, delta } when the newest version (5+ reviews) averages 0.5+ stars below the one before; else null. |
windowComplete30d | Summary rows: true when the history reaches back 30 days, so the 30-day figures are exact; false = based on the newest reviews read. |
windowComplete60d | Summary rows: same for 60 days (reviewsPrior30d). |
historyReviews | Summary rows: reviews remembered for this entity (facts only: date, rating, reply; no text). |
historySince | Summary rows: date of the oldest remembered review. |
stopReason | Summary rows: why reading stopped: 'onlyNew' (reached reviews seen before), 'limit' (max reviews per entity), 'end' (no more reviews), 'budget' or 'error'. |
flags | Summary rows: what needs attention: new_negative, rating_drop, recent_below_lifetime, version_regression, unanswered_negative, velocity_spike. Empty on a baseline. |
code | Error rows: invalid_input, not_found, blocked, unavailable or no_match. |
message | Error rows: what went wrong, in plain words. |
scrapedAt | Error rows: ISO timestamp of the failure. |
Schedule it
In Apify Console, create a Task from your input and add a Schedule (for example daily). Each run writes a new dataset; integrations can push the rows to Google Sheets, Slack, a webhook or your database.