# Agoda Reviews Scraper (`scrapyx/agoda-reviews-scraper`) Actor

Extracts guest review data (ratings, text, reviewer demographics, translations) for hotels listed on Agoda.com by hotel URL or hotel ID.

- **URL**: https://apify.com/scrapyx/agoda-reviews-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Travel, Marketing, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Agoda Reviews Scraper

Extracts guest review data for any hotel listed on Agoda.com — just give it a hotel page link or hotel ID.

### Why use this actor

- No account, no login, and no API key needed — works on public hotel pages only.
- Pulls the full review picture: star ratings, written reviews (with automatic translation to English alongside the original text), reviewer country and trip type, stay dates, and helpful-vote counts.
- Also returns the hotel's aggregate rating summary — overall score, per-category scores (cleanliness, facilities, location, etc.), and combined review counts across providers — as a single summary row per hotel.
- Every hotel you submit gets at least one output row — including a clear diagnostic reason on the rare rows that couldn't be fetched, so nothing silently disappears from your results.
- Works with either a full hotel page URL or just the hotel's numeric ID.
- Built-in cap on reviews per hotel (adjustable) so a single wildly popular hotel with tens of thousands of reviews doesn't blow up your run — set it to 0 to pull everything.

### How it works

1. You give the actor one or more Agoda hotel page links (or numeric hotel IDs).
2. For each hotel, it looks up the review data directly from Agoda, page by page, until it runs out of reviews or hits your per-hotel cap.
3. Results are streamed to your dataset as they finish, with automatic retries for temporary hiccups.
4. You export the finished dataset as JSON, CSV, or Excel straight from the Apify Console — no scrapers or infrastructure to manage yourself.

### Input

```json
{
  "hotelUrls": [
    "https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945"
  ],
  "sortBy": "most_recent",
  "maxReviewsPerHotel": 200,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

| Field | Type | Description |
|---|---|---|
| `hotelUrls` | array of strings | Agoda hotel page URLs (e.g. `https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945`) or raw numeric hotel IDs (e.g. `185945`). |
| `sortBy` | string | Review order: `most_recent` (default), `rating_high_to_low`, `rating_low_to_high`, or `most_helpful`. |
| `maxReviewsPerHotel` | integer | Stop after this many reviews per hotel. Default `200`. Set to `0` to fetch every review (can be slow for hotels with tens of thousands of reviews). |
| `maxConcurrency` | integer | How many hotels to process at the same time. Default `3`. |
| `proxyConfiguration` | object | Proxy settings. Residential proxy is turned on by default and recommended for reliable results. |

### Output

Each hotel produces one **summary** row plus one **review** row per guest review. Real examples from a run against the live site (long fields truncated):

**Summary row** (`recordType: "SUMMARY"`):

```json
{
  "_input": "https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945",
  "_source": "S1-reviews-api",
  "_scrapedAt": "2026-08-09T17:57:50Z",
  "recordType": "SUMMARY",
  "hotelId": 185945,
  "hotelName": "Marina Bay Sands ",
  "combinedReview": {
    "score": {
      "score": 8.9,
      "formattedScore": "8.9",
      "scoreText": "Excellent",
      "reviewCount": 48848,
      "formattedReviewCount": "48,848"
    }
  },
  "score": { "...": "per-category scores (cleanliness, facilities, location, ...) — 3 more fields" }
}
```

**Review row** (`recordType: "REVIEW"`):

```json
{
  "_input": "https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945",
  "_source": "S1-reviews-api",
  "_scrapedAt": "2026-08-09T17:57:50Z",
  "recordType": "REVIEW",
  "hotelId": 185945,
  "hotelName": "Marina Bay Sands ",
  "hotelReviewId": 1158921129,
  "rating": 10.0,
  "formattedRating": "10.0",
  "ratingText": "Exceptional",
  "reviewTitle": "As expected of MBS.",
  "reviewComments": "I had to stop by in order to go to the Maldives, so I simply thought I would stay for a day at the hotel that was said to be the best...",
  "checkInDateMonthAndYear": "July 2026",
  "formattedReviewDate": "August 05, 2026",
  "reviewerInfo": {
    "countryName": "Japan",
    "displayMemberName": "Masaaki",
    "reviewGroupName": "Family with young children",
    "roomTypeName": "Sands Premier Double Queen Gardens by the Bay View Room"
  },
  "helpfulVotes": 0,
  "unHelpfulVotes": 0
}
```

When a hotel can't be found or the input can't be understood, the actor still emits one row for that input with a clear reason, instead of leaving it out silently:

```json
{
  "_input": "999999999",
  "_source": "none",
  "_scrapedAt": "2026-08-09T17:57:50Z",
  "recordType": "ERROR",
  "_error": "not_found",
  "_errorDetail": "No hotel found for hotelId=999999999"
}
```

| Field | Type | Description |
|---|---|---|
| `_input` | string | The hotel URL or ID you submitted. |
| `_source` | string | Which internal strategy produced this row. `"none"` on a failed row. |
| `_scrapedAt` | string | UTC timestamp of when this row was produced. |
| `recordType` | string | `"SUMMARY"`, `"REVIEW"`, or `"ERROR"`. |
| `hotelId` | integer | Agoda's numeric ID for the hotel (present on successful rows). |
| `hotelName` | string | The hotel's name (present on successful rows). |
| `_error` | string | Present only on rows that couldn't be fetched, e.g. `not_found`, `invalid_input`. |
| `_errorDetail` | string | Human-readable detail for the error, present only alongside `_error`. |
| *(all other fields)* | — | On a successful row, every review or rating field Agoda provides is passed through unchanged — the exact set can vary slightly by hotel. |

### Notes / limits

- Very popular hotels can have tens of thousands of reviews. The default 200-per-hotel cap keeps runs fast and predictable; raise it (or set it to `0`) if you need the complete history for a specific property.
- Review text is automatically translated to English by Agoda when the original review is in another language; the original-language text is included alongside the translation.

### Other actors in this collection

| Actor | What it returns |
|---|---|
| Orbitz Hotel Reviews Scraper | Guest reviews for hotels listed on Orbitz.com |

# Actor input Schema

## `hotelUrls` (type: `array`):

Agoda hotel detail page URLs (e.g. https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945) or raw numeric hotel IDs (e.g. 185945).

## `sortBy` (type: `string`):

How reviews are ordered when fetched. Matches the sort options exposed on the Agoda reviews widget itself.

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

Stop paginating a hotel after this many reviews. Popular hotels can have tens of thousands of reviews, so this is capped by default. Set to 0 for unlimited (fetch every review -- can be slow and costly for very-large hotels).

## `maxConcurrency` (type: `integer`):

Maximum number of hotels processed in parallel.

## `proxyConfiguration` (type: `object`):

Residential proxy is recommended for production runs, though the reviews API was not observed to gate on IP reputation during recon.

## Actor input object example

```json
{
  "hotelUrls": [
    "https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945"
  ],
  "sortBy": "most_recent",
  "maxReviewsPerHotel": 200,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "hotelUrls": [
        "https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/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 = { "hotelUrls": ["https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945"] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/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 '{
  "hotelUrls": [
    "https://www.agoda.com/marina-bay-sands/hotel/singapore-sg.html?hotelId=185945"
  ]
}' |
apify call scrapyx/agoda-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/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/CbWao9GccFftMhQFe/builds/v3VlwxNRFZYXtduKL/openapi.json
