# Agoda Hotels Reviews Scraper (`axiomworks/agoda-hotels-reviews-scraper`) Actor

Get Agoda hotel search results and guest reviews in structured records. Hotel fields include names, areas, star and review ratings, review counts, prices, currency, coordinates, and image URLs. Search by city or Agoda URL, then choose hotel records with review arrays or separate review rows.

- **URL**: https://apify.com/axiomworks/agoda-hotels-reviews-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Travel
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.79 / 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?

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 Hotels Reviews Scraper

**Returns:** one row per Agoda hotel with name, city, area, starRating, reviewScore, reviewCount, pricePerNight, currency and an optional reviews array.
**Input:** `{"mode": "hotelsWithReviews", "searchQueries": ["Bangkok"], "maxItems": 10, "maxReviewsPerHotel": 5}`
**Best for:** hotel price monitoring, guest sentiment analysis, travel lead lists and market research on a city's hotels.

```json
{
  "id": "14654101",
  "name": "Solaria Nishitetsu Hotel Bangkok",
  "city": "Bangkok",
  "area": "Sukhumvit",
  "starRating": 4,
  "reviewScore": 9.2,
  "reviewCount": 16009,
  "pricePerNight": 169.23,
  "currency": "USD"
}
```

### What does Agoda Hotels Reviews Scraper do?

Agoda Hotels Reviews Scraper is an Agoda scraper and unofficial Agoda API for hotel search results and guest reviews. Give it one or more city names, Agoda city ids or Agoda page URLs and it returns the hotels for those cities together with the data shown on Agoda: the hotel name, star rating, guest review score, review count, the price per room per night for the stay you choose, the neighbourhood, coordinates, a main photo and the category scores for cleanliness, facilities, location, staff and value.

It can also collect the guest reviews of each hotel. In `hotelsWithReviews` mode every hotel row carries a `reviews` array. In `reviews` mode the Actor returns one row per review instead, which is easier to load into a spreadsheet or a sentiment model. Each review has the rating, title, text, positives, negatives, date, stay month, reviewer country, traveler type, room type, helpful votes and the reply written by the hotel.

You do not need an Agoda account and you do not need to log in. The Actor reads the same public search and review endpoints that the Agoda website uses in a browser. It works sequentially at about one request per second so that it stays polite to the site.

Typical jobs:

- Build a list of all hotels in a city with their ratings and nightly prices.
- Collect recent guest reviews for a set of hotels and analyse what guests praise or complain about.
- Compare neighbourhoods by review score and price.

### What data can you get?

The table lists the fields of a hotel row. Fields are `null` when Agoda does not show a value, for example the price of a hotel that has no availability for your dates.

| Field | Type | Description |
|---|---|---|
| `id` | string | Stable record id, the Agoda property id (propertyId-reviewId in reviews mode) |
| `sourceUrl` | string | Agoda hotel page the row came from |
| `propertyId` | number | Agoda property id |
| `name` | string | Hotel name |
| `url` | string | Agoda hotel page URL |
| `city` | string | City |
| `country` | string | Country |
| `area` | string | Neighbourhood or district |
| `propertyType` | string | Hotel, apartment, hostel and so on |
| `starRating` | number | Star rating, half stars included |
| `reviewScore` | number | Guest score out of 10 |
| `reviewCount` | number | Number of Agoda guest reviews |
| `pricePerNight` | number | Tax-inclusive price per room per night for the searched stay |
| `currency` | string | Currency of the price |
| `latitude`, `longitude` | number | Coordinates |
| `imageUrl` | string | Main photo URL |
| `categoryScores` | object | Scores for cleanliness, facilities, location, staffPerformance, valueForMoney and roomComfort |
| `checkIn`, `nights` | string, number | Stay dates used for the price |
| `reviews` | array | Guest reviews (see below) |

Each entry of the `reviews` array, and each row in `reviews` mode, has these fields:

| Field | Description |
|---|---|
| `reviewId` | Agoda review id |
| `rating` | Rating out of 10 |
| `title` | Review headline |
| `text` | Review comment, empty when the guest only left a rating |
| `positives`, `negatives` | Liked and disliked points when the guest filled them in |
| `reviewDate` | Date and time the review was posted |
| `stayMonth` | Month of the stay |
| `stayCheckIn`, `stayCheckOut` | Guest stay timestamps from the review, including the source timezone |
| `lengthOfStay` | Number of nights reported for the guest stay |
| `hostResponseDate` | Timestamp of the visible hotel reply; null if no reply is returned |
| `reviewerName` | Public display name (optional, see the input table) |
| `reviewerCountry` | Country of the reviewer |
| `travelerType` | Solo traveler, couple, family and so on |
| `roomType` | Room the guest stayed in |
| `helpfulVotes` | Votes that marked the review helpful |
| `hostResponse` | Reply from the hotel when there is one |

In `reviews` mode the row also repeats `propertyId`, `hotelName`, `url`, `city` and `country` so that each review can be used on its own.

### How to use

1. Open the Actor in Apify Console and enter at least one city in **Cities**, for example `Lisbon`.
2. Choose a **Mode**: `hotels` for hotel rows only, `hotelsWithReviews` for hotels with their reviews, or `reviews` for one row per review.
3. Set **Max items**. It limits the number of rows returned: hotels in the hotel modes, reviews in `reviews` mode.
4. Optionally set the check-in date, number of nights, adults, rooms and currency to get prices for a specific stay.
5. Press **Start**. Results appear in the Output tab as they are collected. Download them as JSON, CSV, Excel or HTML, or read them through the API.

A run of 50 hotels without reviews takes well under a minute. Reviews are fetched one page of 20 at a time for every hotel, so runs with many reviews take longer.

You can also paste Agoda URLs into **Start URLs**. A city URL such as `https://www.agoda.com/city/bangkok-th.html` is treated like a city name. A hotel URL such as `https://www.agoda.com/dewan-bangkok-hotel/hotel/bangkok-th.html` returns that hotel and its reviews. For hotel URLs the row contains the hotel id, name, URL and city plus the reviews, because the search listing is not used for a single hotel.

### Input

| Field | Type | Description |
|---|---|---|
| `searchQueries` | array of strings | City names such as `Bangkok`. Required; pass an empty list when you use `cityIds` or `startUrls` |
| `mode` | string | `hotels`, `hotelsWithReviews` or `reviews`. Default `hotels` |
| `maxItems` | integer | Maximum rows to return, default 50 |
| `startUrls` | array | Agoda hotel or city URLs |
| `cityIds` | array of integers | Agoda city ids, for example `9395` for Bangkok |
| `maxReviewsPerHotel` | integer | Reviews per hotel, default 20. `0` gives no reviews in `hotelsWithReviews` mode |
| `reviewSort` | string | `mostRecent`, `ratingHigh`, `ratingLow` or `mostHelpful` |
| `minRating` / `maxRating` | number | Keep only reviews whose `rating` is within this range (Agoda's 1-10 scale). Optional |
| `reviewsSince` | string | Keep only reviews with a `reviewDate` on or after this `YYYY-MM-DD` day. Optional |
| `travelerTypes` | array of strings | Keep only reviews whose `travelerType` contains one of these words, such as `Couple` or `Family`. Optional |
| `reviewKeyword` | string | Keep only reviews whose title, text, positives or negatives contain this phrase. Optional |
| `includeReviewerNames` | boolean | Set to false to leave reviewer names empty. Default true |
| `checkIn` | string | Check-in date `YYYY-MM-DD`. Default is 30 days from today |
| `nights` | integer | Length of stay for the price, default 2 |
| `adults` | integer | Adults for the price, default 2 |
| `rooms` | integer | Rooms for the price, default 1 |
| `currency` | string | Three-letter currency code, default `USD` |
| `proxyConfiguration` | object | Apify Proxy settings, datacenter by default |

Example input:

```json
{
  "mode": "hotelsWithReviews",
  "searchQueries": ["Lisbon"],
  "maxItems": 15,
  "maxReviewsPerHotel": 10,
  "reviewSort": "mostRecent",
  "checkIn": "2026-12-01",
  "nights": 3,
  "adults": 2,
  "currency": "EUR"
}
```

Review filters are applied after each page of reviews is fetched, and `maxReviewsPerHotel` counts reviews that pass the filters, so a run with filters scans more pages per hotel than it returns. A hotel with no matching reviews returns an empty `reviews` array. For example, `{"mode": "reviews", "searchQueries": ["Bangkok"], "maxRating": 5, "reviewKeyword": "noise"}` collects low-rated reviews that mention noise.

Prices depend on the check-in date, the length of stay, the number of guests and the currency. Prices are per room per night and include taxes. The order of hotels follows Agoda's own ranking for the search.

### Output

The dataset holds one item per hotel, or one item per review in `reviews` mode. This is a real item from a run with `mode: hotelsWithReviews`, shortened to one review:

```json
{
  "id": "14654101",
  "sourceUrl": "https://www.agoda.com/solaria-nishitetsu-hotel-bangkok/hotel/bangkok-th.html",
  "propertyId": 14654101,
  "name": "Solaria Nishitetsu Hotel Bangkok",
  "url": "https://www.agoda.com/solaria-nishitetsu-hotel-bangkok/hotel/bangkok-th.html",
  "city": "Bangkok",
  "area": "Sukhumvit",
  "propertyType": "Hotel",
  "starRating": 4,
  "reviewScore": 9.2,
  "reviewCount": 16009,
  "pricePerNight": 169.23,
  "currency": "USD",
  "reviews": [
    {
      "reviewId": 1188226246,
      "rating": 10,
      "title": "Excellent stay with top service",
      "text": "Location was super convenient and room were well maintained and clean.",
      "reviewDate": "2026-09-29T12:13:37+07:00",
      "stayMonth": "September 2026",
      "reviewerCountry": "Singapore",
      "travelerType": "Couple",
      "roomType": "Standard Twin Room",
      "helpfulVotes": 0
    }
  ]
}
```

About half of Agoda reviews have no comment text because the guest only gave a rating. Those reviews are still returned, with `text` set to null. Review text can be in the guest's own language or machine-translated by Agoda. The review also includes the guest stay check-in and check-out timestamps and number of nights when Agoda supplies them. These describe the reviewed stay, separately from the hotel search dates. A visible hotel reply includes its response timestamp when available. These four fields appear inside `reviews` in `hotelsWithReviews` mode and as columns in `reviews` mode; missing values remain null.

### How much does it cost?

The Actor is charged per result: one result for every hotel row saved, or every review row in `reviews` mode. There is no charge for a run that returns nothing. See the Pricing tab of the Actor for the current price, since prices can change. Platform usage such as proxy traffic and compute is shown in your Apify usage as usual. Setting `maxItems` caps the number of results and therefore the cost of a run.

### Use with AI agents (MCP)

You can call this Actor from AI agents through the Apify MCP server. Add this to your MCP client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=axiomworks/agoda-hotels-reviews-scraper"
    }
  }
}
```

Example prompts:

- "List 20 hotels in Lisbon on Agoda with their review score and price per night in EUR."
- "Get the 10 most recent guest reviews for the top 5 hotels in Bangkok on Agoda and summarise the complaints."
- "Find Agoda hotels in Bangkok with a review score above 9 and a nightly price under 60 USD."
- "Fetch the reviews of https://www.agoda.com/dewan-bangkok-hotel/hotel/bangkok-th.html sorted by lowest rating."

### Integrations and API

Run the Actor from code with the Apify API clients.

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("axiomworks/agoda-hotels-reviews-scraper").call(run_input={
    "mode": "hotelsWithReviews",
    "searchQueries": ["Bangkok"],
    "maxItems": 10,
    "maxReviewsPerHotel": 5,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], item["reviewScore"], item["pricePerNight"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('axiomworks/agoda-hotels-reviews-scraper').call({
    mode: 'hotels',
    searchQueries: ['Lisbon'],
    maxItems: 50,
    currency: 'EUR',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const count = items.length;
```

cURL:

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~agoda-hotels-reviews-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "hotels", "searchQueries": ["Bangkok"], "maxItems": 20}'
```

You can schedule runs, send results to Google Sheets, Slack or a webhook, and connect the dataset to tools such as Make or Zapier through the Apify integrations.

### FAQ

**How many hotels can I get for one city?**
As many as Agoda lists for the search, up to your `maxItems`. Large cities have thousands of properties. The Actor pages through the results and stops at `maxItems` or at the end of the list.

**Why is the price empty for some hotels?**
Agoda only shows a price when the hotel has availability for the dates you chose. Hotels that are sold out are skipped in the results, and a few listed hotels have no quote for the stay. Try a different `checkIn` date.

**Why do prices differ from the website?**
Agoda prices depend on dates, number of guests, currency and the visitor's country. The Actor returns the tax-inclusive price per room per night for the stay you ask for, as shown to a visitor without an account.

**Can I get only reviews?**
Yes. Use `mode: reviews` to get one row per review, or paste hotel URLs into `startUrls`. Use `maxReviewsPerHotel` and `reviewSort` to control which reviews you get.

**Why does a review have no text?**
Many guests rate a stay without writing a comment. These reviews keep their rating, date and reviewer country and have a null `text`.

**Can I leave out reviewer names?**
Yes. Set `includeReviewerNames` to false and the `reviewerName` field stays empty.

**The run returned zero items. Why?**
Check the spelling of the city. If no Agoda city matches the name, the Actor logs a warning and finishes with no items. If Agoda blocks the requests, the Actor retries with a new proxy session and fails with a clear message if it cannot get through; switch the proxy to residential in that case.

**Does it need cookies or a login?**
No. Only public search and review data is used.

### Is it legal to scrape Agoda?

This Actor collects publicly visible information, such as hotel details, prices and guest reviews that anyone can see without logging in. It does not access accounts, bookings or private data. Laws differ by country, and the terms of the website may restrict automated access, so you are responsible for how you use the data.

Guest reviews contain public display names and countries of the reviewers, which can count as personal data under rules such as the GDPR. Use the data only for a lawful purpose, keep it secure, and set `includeReviewerNames` to false if you do not need names. This Actor is an independent tool and is not affiliated with or endorsed by Agoda. If you are unsure whether your use case is allowed, ask a legal professional.

### Feedback

If a field is missing, a city is not found or something looks wrong, open an issue from the Actor page in Apify Console and describe the input you used. Feature requests are welcome too.

# Actor input Schema

## `searchQueries` (type: `array`):

City names to search on Agoda, e.g. \['Bangkok', 'Lisbon']. Each name is resolved to an Agoda city. Pass an empty list only if you give cityIds or startUrls instead.

## `mode` (type: `string`):

hotels = one row per hotel; hotelsWithReviews = hotels plus a reviews array; reviews = one row per guest review. Default hotels.

## `maxItems` (type: `integer`):

Maximum number of rows to return (hotels, or reviews in reviews mode), 1-10000, default 50. The run stops once this many are saved.

## `startUrls` (type: `array`):

Optional Agoda hotel URLs (https://www.agoda.com/<slug>/hotel/<city>-<cc>.html) or city URLs (https://www.agoda.com/city/bangkok-th.html). Hotel URLs return that hotel and its reviews.

## `cityIds` (type: `array`):

Optional numeric Agoda city ids, e.g. \[9395] for Bangkok. Use instead of city names if you already know the id.

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

Guest reviews to collect for each hotel, 0-1000, default 20. 0 returns no reviews in hotelsWithReviews mode; reviews mode uses 20 if 0.

## `minRating` (type: `number`):

Only keep reviews rated at least this value on Agoda's 1-10 scale, e.g. 8. Leave empty for no lower limit. Filtering happens after fetching, so reviews scanned can exceed reviews returned.

## `maxRating` (type: `number`):

Only keep reviews rated at most this value on Agoda's 1-10 scale, e.g. 5 to find complaints. Leave empty for no upper limit.

## `reviewsSince` (type: `string`):

Only keep reviews dated on or after this day, YYYY-MM-DD, e.g. '2026-01-01'. Leave empty for all dates.

## `travelerTypes` (type: `array`):

Only keep reviews whose traveler type contains one of these words, e.g. \['Couple', 'Family']. Leave empty for all types.

## `reviewKeyword` (type: `string`):

Only keep reviews whose title, text, positives or negatives contain this word or phrase (case-insensitive), e.g. 'breakfast'.

## `reviewSort` (type: `string`):

Order of reviews: mostRecent, ratingHigh, ratingLow or mostHelpful. Default mostRecent.

## `includeReviewerNames` (type: `boolean`):

Include the public display name of each reviewer. Turn off to leave reviewer names empty (personal data). Default true.

## `checkIn` (type: `string`):

Check-in date YYYY-MM-DD used for prices, e.g. '2026-12-01'. Default is 30 days from today.

## `nights` (type: `integer`):

Length of stay in nights for price quotes, 1-30, default 2.

## `adults` (type: `integer`):

Number of adults for price quotes, 1-12, default 2.

## `rooms` (type: `integer`):

Number of rooms for price quotes, 1-8, default 1.

## `currency` (type: `string`):

3-letter currency code for prices, e.g. 'USD' or 'EUR'. Default USD.

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

Apify Proxy settings. Datacenter proxy is the default and works for most runs; switch to residential if Agoda blocks requests.

## Actor input object example

```json
{
  "searchQueries": [
    "Bangkok"
  ],
  "mode": "hotelsWithReviews",
  "maxItems": 10,
  "startUrls": [],
  "cityIds": [],
  "maxReviewsPerHotel": 5,
  "reviewSort": "mostRecent",
  "includeReviewerNames": true,
  "nights": 2,
  "adults": 2,
  "rooms": 1,
  "currency": "USD",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

One record per Agoda hotel, or per review in reviews mode.

# 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 = {
    "searchQueries": [
        "Bangkok"
    ],
    "mode": "hotelsWithReviews",
    "maxItems": 10,
    "maxReviewsPerHotel": 5,
    "nights": 2,
    "currency": "USD",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/agoda-hotels-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 = {
    "searchQueries": ["Bangkok"],
    "mode": "hotelsWithReviews",
    "maxItems": 10,
    "maxReviewsPerHotel": 5,
    "nights": 2,
    "currency": "USD",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/agoda-hotels-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 '{
  "searchQueries": [
    "Bangkok"
  ],
  "mode": "hotelsWithReviews",
  "maxItems": 10,
  "maxReviewsPerHotel": 5,
  "nights": 2,
  "currency": "USD",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call axiomworks/agoda-hotels-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/agoda-hotels-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/13YqRcmmPcS6BVn3D/builds/tx1vydakdD9zietTc/openapi.json
