# Agoda Reviews Scraper - Bulk Hotels & New Reviews Only (`neverempty/agoda-reviews-scraper`) Actor

For hotel revenue managers, reputation agencies and review analysts: Agoda reviews with rating, date, text, pros and cons, language, reviewer country, traveler type, room, stay and hotel reply, plus Booking.com reviews. 5 of 5 matched the Agoda page. Many hotels per run; monitoring: new ones only.

- **URL**: https://apify.com/neverempty/agoda-reviews-scraper.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Travel, Automation, Developer tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 review returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Agoda Reviews Scraper - Bulk Hotels & New Reviews Only

For hotel revenue managers, reputation agencies and review analysts: every review Agoda shows for a hotel - rating, date, title, text, pros and cons, language, reviewer country, traveler type, room, stay dates and the hotel's reply - including the Booking.com and Priceline.com reviews Agoda displays, each marked with the site it came from. In a check on 2026-09-21, 5 of 5 reviews matched the Agoda hotel page opened in a browser (rating, reviewer, room, stay, title, text and date), and one run returned 1,105 of the 1,105 reviews Agoda listed for a Dublin hotel, with no duplicates. Give it a list of hotels in one run, and in monitoring mode it returns only the reviews you have not received yet, so you never type a start date.

Unofficial. Public data only.

Export as JSON, CSV or Excel.

### What you get

- **One row per review**, for as many hotels as you list (`hotels`): review ID, rating out of 10 and Agoda's word for it, review date, title, text, pros and cons (Booking.com reviews), language, reviewer display name and country, traveler type (Couple, Family with young children, Solo traveler...), room type, check-in and check-out dates, nights, helpful votes, the hotel's reply and its date, and photo links.
- **Reviews from other sites, marked** (`includeOtherSites`): Agoda also shows reviews it takes from Booking.com and Priceline.com. Each row says where it comes from (`reviewSite`, `isAgodaReview`), so you can keep or drop them.
- **Original language and Agoda's translation**: `title` and `text` are what the guest wrote; when Agoda shows an English translation, it is in `titleTranslated` and `textTranslated`.
- **Monitoring mode** (`monitoringMode`): run it on a schedule and get back only reviews this watch has not returned before. No start date to type and no diffing on your side.
- **No failed runs for "nothing found".** A hotel that does not exist, a hotel with no reviews, a refused request or a spending limit each come back as a free row that says why.

### Input

| Field | What it does |
|---|---|
| `hotels` | Agoda hotel page URLs (`https://www.agoda.com/marine-hotel/hotel/dublin-ie.html`) or Agoda hotel IDs (`6`), as many as you like (up to 200 per run). |
| `maxReviewsPerHotel` | Reviews to return per hotel, 1-100,000. Empty = 200. In monitoring mode this caps only the first run. |
| `includeOtherSites` | On or empty = also return the Booking.com and Priceline.com reviews Agoda shows. Off = only reviews written on Agoda. |
| `monitoringMode` | Return only reviews this watch has not returned before. |
| `resetMonitoringState` | Forget what this watch remembered for these hotels at the start of this run, so this run starts over like a first run. Turn it off again for scheduled runs, or every run starts over and returns the same reviews again. |

### Output

```json
{
  "source": "agoda",
  "status": "ok",
  "hotelId": 6,
  "hotelName": "Marine Hotel",
  "hotelReviewsUrl": "https://www.agoda.com/marine-hotel/reviews/dublin-ie.html",
  "inputHotel": "https://www.agoda.com/marine-hotel/hotel/dublin-ie.html",
  "reviewId": "1173899868",
  "reviewSite": "Agoda",
  "reviewSiteId": 332,
  "isAgodaReview": true,
  "rating": 8,
  "ratingText": "Excellent",
  "reviewDate": "2026-08-31",
  "reviewDateTime": "2026-08-31T03:10:18+07:00",
  "title": "Dublin Bay",
  "text": "No issues...very pleasant stay...lovely views of Dublin Bay..staff very good....lovely walks...good transport links to city  centre.",
  "positives": null,
  "negatives": null,
  "language": "en",
  "titleTranslated": null,
  "textTranslated": null,
  "translatedTo": null,
  "reviewerName": "Steve",
  "reviewerCountry": "United Kingdom",
  "reviewerCountryCode": "GB",
  "travelerType": "Couple",
  "roomType": "Standard Double Room",
  "nightsStayed": 1,
  "checkInDate": "2026-08-30",
  "checkOutDate": "2026-08-31",
  "stayMonth": "August 2026",
  "helpfulVotes": 0,
  "hotelResponse": null,
  "hotelResponseDate": null,
  "photoUrls": [],
  "scrapedAt": "2026-09-21T11:08:02.000Z"
}
```

Rows that are not reviews have a `status` other than `ok` and a `note` that says why: `no-such-hotel`, `no-reviews`, `blocked`, `unreadable`, `bad-input`, `budget-reached` or, in monitoring mode, `no-new-since-last-run`. These rows are never charged.

### Things worth knowing

- **Order.** Agoda sorts each review site's list newest first, but in blocks by language (for example all English Booking.com reviews newest first, then the Spanish ones, then the French ones). The Actor reads the list 100 reviews per site at a time and returns each batch newest first, so a small `maxReviewsPerHotel` can stop before a recent review in a less common language. Monitoring reads the whole list (up to 100 pages of 100 per site), so it does not miss those.
- **Two copies of the list.** In our checks on 2026-09-21, Agoda served different visitors two different copies of the same hotel's review list; for a Dublin hotel, one copy lacked the hotel's two newest reviews. The Actor asks with several fresh sessions per hotel until it finds both copies (up to 8 for the first hotel, 2 more for each later hotel until two copies turn up), reads both and merges them by review ID, so every review appears once. If every session happens to land on the same copy, that run reads only that copy.
- **Monitoring details.** The first monitoring run returns the newest reviews up to `maxReviewsPerHotel` and remembers the rest of the list without returning or charging them. Reviews dated from 2 days before the watch first read a hotel onward are always returned, even if the first run did not get through the whole list. Later runs return every review not seen before. A review dated more than 30 days before the watch started that shows up for the first time (for example because Agoda's other copy of the list had it) is remembered but not returned. Do not put the same hotels in two schedules that run at the same moment: the memory cannot be updated atomically, so overlapping runs may return a review twice.
- **Speed.** In 2026-09-21 checks, a hotel with 1,105 reviews took 55-70 seconds per run (both copies of the list, every page, with a one-second pause between requests), and three hotels with 1,641 reviews in total took 2 minutes. Monitoring reads the whole list each time, so a check takes as long as a full read: about 70 hotels of that size per hour. The run timeout is set to 4 hours by default; raise it in the run options for longer lists of hotels.
- **Reviewer names** are the display names Agoda shows publicly (often a first name only). Email addresses and phone numbers written inside a review are replaced with a placeholder.
- **What Booking.com reviews carry.** In the 2026-09-21 run above, 1,581 of 1,641 rows were Booking.com reviews shown on Agoda. Those have a title, pros and cons, rating, date, display name and traveler type, but Agoda does not show their reviewer country, room, stay dates or a single review text (country, room and stay dates were filled in 3% of all rows - the Agoda reviews). Empty values are null, never 0 or an empty string.
- **Empty answers.** From Apify's servers Agoda sometimes answers with an empty list for a page that exists (3 of 10 identical requests in a 2026-09-21 check). The Actor asks again, up to 10 times with growing pauses, instead of treating it as the end of the list; if it still gets nothing, a free row says which pages were read.
- **Checks and refusals.** If Agoda shows a check page or refuses a request, the run stops and says so in a free row. The Actor does not try to get around Agoda's checks.

### Pricing

Pay per event:

- **Run start: $0.02 per run** on the Free plan, down to $0.0146 on higher Apify plans (Bronze $0.0182, Silver $0.0164, Gold $0.0146). Charged once for every run that requests anything - including a run that finds no new reviews, and a run Agoda refuses. It is charged before the first request, so a run whose maximum total charge has no room for the start fee plus one review row (in monitoring mode, plus one hotel check) requests nothing and is charged nothing. A run Apify restarts or moves is charged once.
- **Review row: $5.00 per 1,000** on the Free plan, down to $3.50 per 1,000 on higher Apify plans (Bronze $4.50, Silver $4.00, Gold $3.50).
- **Monitoring check: $0.30 per 1,000** hotels checked (only in monitoring mode, once per hotel per run, whether or not it had new reviews).
- Free rows (no such hotel, no reviews, refused, no new reviews, limit reached) are never charged. Set a maximum total charge on the run and the Actor stops before going over it, with a free row saying what was left out.

# Actor input Schema

## `hotels` (type: `array`):

Agoda hotel page URLs (https://www.agoda.com/marine-hotel/hotel/dublin-ie.html) or Agoda hotel IDs (6). Add as many hotels as you like in one run; each hotel's reviews come back as separate rows with its hotelId and hotelName. A URL that does not lead to a hotel comes back as a free row that says so.

## `maxReviewsPerHotel` (type: `integer`):

How many reviews to return for each hotel, newest first within each review site and language. Empty = 200. In monitoring mode this caps only the first run; later runs return every new review.

## `includeOtherSites` (type: `boolean`):

Agoda also shows reviews it takes from Booking.com and Priceline.com. On (or empty) = return them too, with reviewSite saying where each one comes from. Off = only reviews written on Agoda.

## `monitoringMode` (type: `boolean`):

Return only reviews this watch has not returned before, so you never type a start date. The first run returns the newest reviews up to maxReviewsPerHotel and remembers the rest without returning them. Each hotel checked costs the small check fee; new reviews cost the review price.

## `resetMonitoringState` (type: `boolean`):

Forget what this watch remembered for these hotels at the start of this run, so this run starts over like a first run. Turn it off again for scheduled runs, or every run starts over and returns the same reviews again.

## Actor input object example

```json
{
  "hotels": [
    "https://www.agoda.com/marine-hotel/hotel/dublin-ie.html"
  ]
}
```

# Actor output Schema

## `results` (type: `string`):

One row per review for each hotel: review ID, review site (Agoda, Booking.com or Priceline.com), rating, date, title, text, pros and cons, language and Agoda's English translation, reviewer display name and country, traveler type, room, stay dates and nights, helpful votes, the hotel's reply and photo links. In monitoring mode, only reviews the watch has not returned before. Hotels that do not exist, hotels with no reviews, refused requests and runs that hit their maximum charge come back as free rows that say why.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "hotels": [
        "https://www.agoda.com/marine-hotel/hotel/dublin-ie.html"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/agoda-reviews-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "hotels": ["https://www.agoda.com/marine-hotel/hotel/dublin-ie.html"] }

# Run the Actor and wait for it to finish
run = client.actor("neverempty/agoda-reviews-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "hotels": [
    "https://www.agoda.com/marine-hotel/hotel/dublin-ie.html"
  ]
}' |
apify call neverempty/agoda-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/agoda-reviews-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hHt97VWZZMcuGv3SG/builds/rK4yHmCG0eu0wfZFk/openapi.json
