# Agoda Hotel Scraper (`crawlio/agoda-hotel-scraper`) Actor

Extract 1,000 Agoda hotel results for $0.75🔥. Collect hotel search results, property details, live room prices, availability, ratings, reviews, amenities, and booking information.

- **URL**: https://apify.com/crawlio/agoda-hotel-scraper.md
- **Developed by:** [Crawlio](https://apify.com/crawlio) (community)
- **Categories:** Travel, Lead generation, Automation
- **Stats:** 6 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 search 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 Hotel Scraper

Agoda Hotel Scraper extracts hotel search results, property details, room pricing, availability, and guest reviews from [Agoda](https://www.agoda.com). It is built for travel research, hotel market analysis, pricing monitoring, lead generation, and review analysis.

<section>
<h2>What Can It Scrape?</h2>

<ul>
  <li>Hotel search results for a destination query or Agoda city ID</li>
  <li>Filtered hotel lists using Agoda-style search filters</li>
  <li>Single-property details from an Agoda property ID or property URL</li>
  <li>Pricing, room availability, room offers, images, policies, and location data</li>
  <li>Paginated guest reviews with reviewer metadata and review scores</li>
</ul>
</section>

### Use Cases

- Compare hotel pricing and availability across destinations.
- Monitor competitor properties, ratings, and review counts.
- Collect room-level pricing and availability for market research.
- Analyze guest sentiment, review volume, and review trends.
- Build hotel datasets for travel dashboards or internal analytics.

### Quick Start

1. Open the Actor on Apify and click **Try for free**.
2. Choose a `mode`: `search`, `property`, or `reviews`.
3. Fill in the matching configuration section.
4. Click **Run**.
5. Open the **Dataset** tab to preview or download the results.

### Supported Modes

<table>
  <thead>
    <tr>
      <th>Mode</th>
      <th>Use it for</th>
      <th>Main input</th>
      <th>Dataset output</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>search</code></td>
      <td>Hotel search results for a destination</td>
      <td><code>search.query</code> or <code>search.cityId</code></td>
      <td>One item per hotel result</td>
    </tr>
    <tr>
      <td><code>property</code></td>
      <td>Details for one Agoda property</td>
      <td><code>property.propertyId</code> or <code>property.propertyUrl</code></td>
      <td>One item for the property</td>
    </tr>
    <tr>
      <td><code>reviews</code></td>
      <td>Guest reviews for one Agoda property</td>
      <td><code>reviews.propertyId</code> or <code>reviews.propertyUrl</code></td>
      <td>One item per review</td>
    </tr>
  </tbody>
</table>

### Input Configuration

#### Global Settings

<table>
  <thead>
    <tr>
      <th>Field</th>
      <th>Default</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>mode</code></td>
      <td><code>search</code></td>
      <td>Operation to run. Use <code>search</code>, <code>property</code>, or <code>reviews</code>.</td>
    </tr>
    <tr>
      <td><code>origin</code></td>
      <td><code>US</code></td>
      <td>Two-letter origin country code sent to Agoda.</td>
    </tr>
    <tr>
      <td><code>languageLocale</code></td>
      <td><code>en-us</code></td>
      <td>Agoda language locale.</td>
    </tr>
    <tr>
      <td><code>currency</code></td>
      <td><code>USD</code></td>
      <td>Currency code used for prices.</td>
    </tr>
  </tbody>
</table>

#### Hotel Search Settings

Use `mode: "search"` to collect hotel listings. You can provide a destination query and let the Actor resolve it, or pass an Agoda `cityId` directly.

<table>
  <thead>
    <tr>
      <th>Field</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>search.query</code></td>
      <td>Destination text such as <code>Bangkok</code>, <code>Krabi</code>, or <code>Kuala Lumpur</code>.</td>
    </tr>
    <tr>
      <td><code>search.cityId</code></td>
      <td>Agoda city ID. Prefer this when you need exact destination control.</td>
    </tr>
    <tr>
      <td><code>search.checkIn</code>, <code>search.checkOut</code></td>
      <td>Dates in <code>YYYY-MM-DD</code> format. Leave empty to use automatic upcoming dates.</td>
    </tr>
    <tr>
      <td><code>search.adults</code>, <code>search.children</code>, <code>search.childAges</code>, <code>search.rooms</code></td>
      <td>Guest and room configuration. Use comma-separated child ages, for example <code>4,8</code>.</td>
    </tr>
    <tr>
      <td><code>search.limit</code>, <code>search.offset</code></td>
      <td>Pagination controls. <code>limit</code> controls returned unique hotels, and <code>offset</code> skips results.</td>
    </tr>
  </tbody>
</table>

Available search filters include `propertyType`, `starRatingMin`, `reviewScoreMin`, `cityCenterDistance`, `freeCancellation`, `payAtHotel`, `bookNowPayLater`, `bookWithoutCreditCard`, `payNow`, `breakfastIncluded`, `outsideFoodDeliveryAllowed`, `earlyCheckIn`, `dinnerIncluded`, `swimmingPool`, `internet`, `parking`, `airportTransfer`, and `gymFitness`.

<details>
<summary><strong>Hotel search example input</strong></summary>

```json
{
  "mode": "search",
  "search": {
    "query": "Krabi",
    "checkIn": "2026-06-01",
    "checkOut": "2026-06-03",
    "adults": 2,
    "children": 0,
    "childAges": "",
    "rooms": 1,
    "limit": 10,
    "offset": 0,
    "propertyType": "hotel",
    "starRatingMin": "4",
    "reviewScoreMin": "8",
    "freeCancellation": true,
    "breakfastIncluded": true,
    "swimmingPool": true
  },
  "origin": "US",
  "languageLocale": "en-us",
  "currency": "USD"
}
```

</details>

#### Property Details Settings

Use `mode: "property"` when you need detailed information for one Agoda property. Provide either `property.propertyId` or `property.propertyUrl`.

<details>
<summary><strong>Property details example input</strong></summary>

```json
{
  "mode": "property",
  "property": {
    "propertyUrl": "https://www.agoda.com/grande-centre-point-surawong-bangkok/hotel/bangkok-th.html",
    "checkIn": "2026-06-01",
    "checkOut": "2026-06-03",
    "adults": 2,
    "children": 0,
    "childAges": "",
    "rooms": 1,
    "enrichPricing": false
  },
  "origin": "US",
  "languageLocale": "en-us",
  "currency": "USD"
}
```

</details>

Set `property.enrichPricing` to `true` when you need richer room pricing details such as room IDs, supplier IDs, benefits, cashback, and occupancy metadata.

#### Property Reviews Settings

Use `mode: "reviews"` to collect paginated guest reviews for one Agoda property. Provide either `reviews.propertyId` or `reviews.propertyUrl`.

<details>
<summary><strong>Property reviews example input</strong></summary>

```json
{
  "mode": "reviews",
  "reviews": {
    "propertyUrl": "https://www.agoda.com/grande-centre-point-surawong-bangkok/hotel/bangkok-th.html",
    "limit": 20,
    "offset": 0,
    "sortBy": "newest"
  },
  "origin": "US",
  "languageLocale": "en-us",
  "currency": "USD"
}
```

</details>

### Output

The Actor writes records to the default dataset for hotel search runs and to the `results` dataset for property and review runs. A compact run summary is also saved to the default key-value store under the `OUTPUT` record.

#### Hotel Search Output Example

```json
{
  "property_id": 44842960,
  "type": "NormalProperty",
  "name": "Grande Centre Point Surawong Bangkok",
  "rating": 5.0,
  "accommodation_type": 34,
  "city": "Bangkok",
  "country_code": "TH",
  "property_url": "https://www.agoda.com/grande-centre-point-surawong-bangkok/hotel/bangkok-th.html",
  "lat": 13.725975,
  "lng": 100.518982,
  "review_score": 9.3,
  "review_count": 13061,
  "is_available": true,
  "price_per_night_incl": 118.42,
  "price_per_night_excl": 100.62,
  "crossed_out_price": 0.0,
  "currency": "USD",
  "resultType": "hotel_search_result",
  "city_id": 9395,
  "query": "Bangkok"
}
```

#### Property Output Example

```json
{
  "property_id": 44842960,
  "name": "Grande Centre Point Surawong Bangkok",
  "address": "299 Thanon Surawong",
  "city": "Bangkok",
  "country": "Thailand",
  "country_code": "th",
  "stars": 5.0,
  "is_available": true,
  "is_ready": true,
  "pricing_enriched": false,
  "pricing_quote": {
    "check_in": "2026-06-01",
    "check_out": "2026-06-03",
    "adults": 2,
    "children": 0,
    "rooms_requested": 1,
    "currency": "USD",
    "room_count": 1
  },
  "rooms": [
    {
      "room_name": null,
      "total_incl": 118.42,
      "total_excl": 100.62,
      "crossed_out": 0.0,
      "benefits": []
    }
  ],
  "resultType": "property"
}
```

#### Review Output Example

```json
{
  "property_id": 44842960,
  "hotel_name": "Grande Centre Point Surawong Bangkok",
  "star_rating": 5.0,
  "combined_score": 9.3,
  "combined_score_text": "Exceptional",
  "review_count": 13061,
  "review_id": 1073109886,
  "provider_id": 332,
  "title": "Loved everything about this hotel",
  "comment": "The room that we booked was massive with a great ceiling to floor glass window.",
  "score": 10.0,
  "score_text": "Exceptional",
  "review_date": "Feb 07, 2026",
  "reviewer_name": "Czarina",
  "reviewer_country": "United Kingdom",
  "demographic": "Couple",
  "room_type_name": "Premium King Room",
  "resultType": "review"
}
```

### Destination Resolution Notes

- Use `search.query` for convenient destination lookup.
- Use `search.cityId` when exact destination matching matters.
- Agoda may return neighborhoods, landmarks, or properties for specific destination text. When that happens, the Actor searches the parent city where possible.
- Neighborhood-specific filtering is not currently exposed as a separate input field.

### Tips

- Keep `limit` small for first tests, then increase it after verifying the result shape.
- Provide exact dates when comparing pricing across multiple runs.
- Use `cityId` for repeatable destination targeting.
- Use `offset` with `limit` for paginated collection.
- Provide exactly one child age per child when `children` is greater than `0`.
- Enable `enrichPricing` only when room-level pricing metadata is required, because it can increase runtime.

### Troubleshooting

<table>
  <thead>
    <tr>
      <th>Issue</th>
      <th>What to check</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>No results</td>
      <td>Check destination, dates, guest count, filters, and whether the property has availability.</td>
    </tr>
    <tr>
      <td>Input validation failed</td>
      <td>Check date format, required property IDs or URLs, child age count, and selected mode.</td>
    </tr>
    <tr>
      <td>Agoda rejected or limited requests</td>
      <td>Retry later, lower request volume, or enable proxy settings in Apify.</td>
    </tr>
    <tr>
      <td>Unexpected destination</td>
      <td>Use an explicit Agoda <code>cityId</code> instead of a broad destination query.</td>
    </tr>
  </tbody>
</table>

### Legal Notice

Personal data may be protected by GDPR in the European Union and by other privacy regulations around the world. Only scrape and process personal data when you have a legitimate reason to do so. If you are unsure, consult a qualified legal professional.

For more general guidance, read Apify's article: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

# Actor input Schema

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

Choose what to extract from Agoda.

## `search` (type: `object`):

Configure settings for Agoda hotel search.

## `property` (type: `object`):

Configure settings for a single Agoda property.

## `reviews` (type: `object`):

Configure settings for Agoda property reviews.

## `origin` (type: `string`):

Two-letter Agoda origin country code sent in request headers.

## `languageLocale` (type: `string`):

Agoda language locale header value.

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

Currency code for prices.

## Actor input object example

```json
{
  "mode": "search",
  "search": {
    "query": "Kuala Lumpur",
    "checkIn": "",
    "checkOut": "",
    "adults": 2,
    "children": 0,
    "childAges": "",
    "rooms": 1,
    "limit": 20,
    "offset": 0,
    "propertyType": "any",
    "starRatingMin": "0",
    "reviewScoreMin": "0",
    "cityCenterDistance": "any"
  },
  "property": {
    "propertyId": 87219375,
    "propertyUrl": "",
    "checkIn": "",
    "checkOut": "",
    "adults": 2,
    "children": 0,
    "childAges": "",
    "rooms": 1,
    "enrichPricing": false
  },
  "reviews": {
    "propertyId": 61727253,
    "propertyUrl": "",
    "limit": 20,
    "offset": 0,
    "sortBy": "newest"
  },
  "origin": "US",
  "languageLocale": "en-us",
  "currency": "USD"
}
```

# Actor output Schema

## `runSummary` (type: `string`):

Summary stored in the OUTPUT record of the default key-value store, including the active output id for this run.

## `searchResults` (type: `string`):

Default dataset used by hotel search runs.

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

Results dataset used by property details and reviews runs.

# 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 = {
    "search": {
        "query": "Kuala Lumpur",
        "checkIn": "",
        "checkOut": "",
        "adults": 2,
        "children": 0,
        "childAges": "",
        "rooms": 1,
        "limit": 20,
        "offset": 0,
        "propertyType": "any",
        "starRatingMin": "0",
        "reviewScoreMin": "0",
        "cityCenterDistance": "any"
    },
    "property": {
        "propertyId": 87219375,
        "propertyUrl": "",
        "checkIn": "",
        "checkOut": "",
        "adults": 2,
        "children": 0,
        "childAges": "",
        "rooms": 1,
        "enrichPricing": false
    },
    "reviews": {
        "propertyId": 61727253,
        "propertyUrl": "",
        "limit": 20,
        "offset": 0,
        "sortBy": "newest"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlio/agoda-hotel-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 = {
    "search": {
        "query": "Kuala Lumpur",
        "checkIn": "",
        "checkOut": "",
        "adults": 2,
        "children": 0,
        "childAges": "",
        "rooms": 1,
        "limit": 20,
        "offset": 0,
        "propertyType": "any",
        "starRatingMin": "0",
        "reviewScoreMin": "0",
        "cityCenterDistance": "any",
    },
    "property": {
        "propertyId": 87219375,
        "propertyUrl": "",
        "checkIn": "",
        "checkOut": "",
        "adults": 2,
        "children": 0,
        "childAges": "",
        "rooms": 1,
        "enrichPricing": False,
    },
    "reviews": {
        "propertyId": 61727253,
        "propertyUrl": "",
        "limit": 20,
        "offset": 0,
        "sortBy": "newest",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlio/agoda-hotel-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 '{
  "search": {
    "query": "Kuala Lumpur",
    "checkIn": "",
    "checkOut": "",
    "adults": 2,
    "children": 0,
    "childAges": "",
    "rooms": 1,
    "limit": 20,
    "offset": 0,
    "propertyType": "any",
    "starRatingMin": "0",
    "reviewScoreMin": "0",
    "cityCenterDistance": "any"
  },
  "property": {
    "propertyId": 87219375,
    "propertyUrl": "",
    "checkIn": "",
    "checkOut": "",
    "adults": 2,
    "children": 0,
    "childAges": "",
    "rooms": 1,
    "enrichPricing": false
  },
  "reviews": {
    "propertyId": 61727253,
    "propertyUrl": "",
    "limit": 20,
    "offset": 0,
    "sortBy": "newest"
  }
}' |
apify call crawlio/agoda-hotel-scraper --silent --output-dataset

```

## MCP server setup

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