Arcadium Data Scrapers
Home / Guides / Review Monitor

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)

  1. Open arcadium/reputation-monitor and sign in to Apify (a free account works).
  2. Fill in the input form. The fields below are the ones the example uses.
  3. Set a maximum cost per run in the run options if you want a hard cap.
  4. Start the run. Rows appear in the Output tab as they arrive.
  5. Export the dataset as JSON, CSV or Excel, or connect an integration.
Input fieldTypeDescription
startUrlsarrayExample: ["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.
maxReviewsPerEntityintegerExample: 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"
  ]
}
FieldWhat it holds
rowTypeKind 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).
platformSource: booking, tripadvisor, googleplay, appstore, yelp, capterra or trustradius.
entityIdNative id of the entity on its source (hotel id, place id, app id, business id, product id).
inputThe URL you entered for this entity.
checkedAtISO timestamp of this run's check.
entityNameAlert rows: name of the hotel, business, app or product.
entityUrlAlert rows: public page of the entity.
reviewIdAlert rows: stable review id '<Platform>___<native id>'.
reviewUrlAlert rows: public link to the review, null when the source has none.
dateAlert rows: review date (YYYY-MM-DD).
titleAlert rows: review title, null when the source has none. Personal data is redacted.
textAlert rows: review text. Emails, phone numbers and names in greetings are redacted.
prosAlert rows: what the reviewer liked (Booking, Capterra, TrustRadius), null elsewhere.
consAlert rows: what the reviewer disliked (Booking, Capterra, TrustRadius), null elsewhere.
languageAlert rows: review language code when the source states it.
appVersionAlert rows: app version the review was written for (app stores), null elsewhere.
ownerRepliedAlert rows: true when the owner or developer has already replied.
ownerReplyAlert rows: the owner's reply text (redacted), null when there is none.
changeTypeAlert rows: 'new' = first seen this run; 'edited' = a known review whose rating was edited down into the alert band.
statusSummary rows: 'baseline' (first run, history recorded, no alerts), 'changed' (new or edited reviews) or 'unchanged'.
nameSummary rows: name of the hotel, business, app or product.
urlSummary rows: public page of the entity.
previousCheckAtSummary rows: ISO timestamp of the previous run with this watchlist name, null on a baseline.
ratingRating on 1-5 (Booking and TrustRadius 1-10 scores are halved) as the source states it now. Alert rows: the review's rating.
previousRatingSummary rows: the source's average rating at the previous run.
ratingChangeSummary rows: rating minus previousRating (stars). Negative = the average went down.
reviewCountSummary rows: review count the source states (app stores: the number of star ratings).
previousReviewCountSummary rows: reviewCount at the previous run.
reviewCountChangeSummary rows: reviewCount minus previousReviewCount, the true number of new reviews/ratings even beyond the read limit.
newReviewsSummary rows: reviews first seen this run (0 on a baseline).
editedReviewsSummary rows: known reviews whose text or rating changed since they were seen.
newNegativeReviewsSummary rows: alert rows written for this entity this run.
newReviewsAvgRatingSummary rows: average rating of this run's new and edited reviews, null when there are none.
avgRating30dSummary rows: average rating of the reviews dated in the last 30 days (from the remembered history).
previousAvgRating30dSummary rows: avgRating30d at the previous run.
reviews7dSummary rows: reviews dated in the last 7 days.
reviews30dSummary rows: reviews dated in the last 30 days (a lower bound when windowComplete30d is false).
reviewsPrior30dSummary rows: reviews dated 31-60 days ago, to compare velocity.
reviewsPerWeekSummary rows: review velocity, reviews30d per week.
avgRatingLifetimeSummary 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.
lifetimeSourceSummary rows: 'site' (the source's stated average) or 'sample' (average of the remembered reviews).
rating30dVsLifetimeSummary rows: avgRating30d minus avgRatingLifetime. Negative = recent reviews are worse than usual.
ownerReplyRate90dSummary rows: share (0-1) of the last 90 days' reviews with an owner reply; null on TrustRadius (no replies).
replySample90dSummary rows: number of reviews ownerReplyRate90d is based on.
medianReplyLagDaysSummary rows: median days from review to owner reply (Tripadvisor, Yelp, app stores); null where the source does not date replies.
replyLagSampleSummary rows: number of replies medianReplyLagDays is based on.
unansweredNegative30dSummary rows: reviews of the last 30 days at or below the alert rating without an owner reply.
appVersionsSummary rows (apps): up to 5 newest versions in the history: [{ version, reviews, avgRating, firstSeen }].
versionRegressionSummary 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.
windowComplete30dSummary rows: true when the history reaches back 30 days, so the 30-day figures are exact; false = based on the newest reviews read.
windowComplete60dSummary rows: same for 60 days (reviewsPrior30d).
historyReviewsSummary rows: reviews remembered for this entity (facts only: date, rating, reply; no text).
historySinceSummary rows: date of the oldest remembered review.
stopReasonSummary rows: why reading stopped: 'onlyNew' (reached reviews seen before), 'limit' (max reviews per entity), 'end' (no more reviews), 'budget' or 'error'.
flagsSummary rows: what needs attention: new_negative, rating_drop, recent_below_lifetime, version_regression, unanswered_negative, velocity_spike. Empty on a baseline.
codeError rows: invalid_input, not_found, blocked, unavailable or no_match.
messageError rows: what went wrong, in plain words.
scrapedAtError 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.