# Agoda Hotel Search Scraper (`romy/agoda-hotel-search-scraper`) Actor

Search Agoda hotels by destination or city id with real filters and sorting: stars, price, review score, free cancellation, breakfast, facilities. No login needed.

- **URL**: https://apify.com/romy/agoda-hotel-search-scraper.md
- **Developed by:** [Romy](https://apify.com/romy) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Hotel Search Scraper

Search [Agoda](https://www.agoda.com) hotels for a destination or a known city id and
get a clean dataset of hotels back — no login, account, app or device needed. Spun off
from the [Agoda All-in-One API](https://github.com/RomySaputraSihananda/agoda-all-in-one-api)
for teams that want a run-and-export dataset instead of a live API: give it a place and
dates, get a deduped list of hotels with price, rating and location.

### Why use this Actor?

- **Rate shopping / market scans** — pull every hotel in a city for a stay, with price,
  star rating and guest review score, ready for your own spreadsheet or BI tool.
- **Filtered sourcing** — narrow by stars, price range, review score, free cancellation,
  breakfast, facilities and more before you ever open the site.
- **Bulk destination coverage** — resolve a free-text place name to Agoda's own city id
  automatically, so you don't need to look up ids by hand.

### Input

| Field | Required | Description |
| --- | --- | --- |
| `destination` | one of `destination`/`cityId` | Free-text place name, e.g. `"Bangkok"`. Resolved to a cityId via Agoda's own autocomplete. |
| `cityId` | one of `destination`/`cityId` | Agoda city id, used directly (skips the autocomplete call). Known-working example: `9395` (Bangkok). |
| `checkin` | yes | Check-in date, `YYYY-MM-DD`. |
| `checkout` | no | Check-out date. If given, overrides `los` (`los` = checkout - checkin). |
| `los` | no | Length of stay in nights, 1-30 (default 1). Ignored if `checkout` is given. |
| `adults` | no | Adults per room (default 2). |
| `rooms` | no | Number of rooms (default 1). |
| `children` | no | Children per room (default 0). |
| `childrenAges` | no | Ages of each child. Padded with age 8 / truncated to match `children` if the count differs. |
| `currency` | no | ISO currency code for prices (default `USD`). |
| `locale` | no | Response language as an Agoda locale, e.g. `th-th`, `en-us` (default). |
| `sortField` / `sortOrder` / `sortLandmarkId` | no | Sort the upstream result. See "Sort fields" below — only fields verified to actually reorder results are offered. |
| `maxResults` | no | Stop after this many unique hotels, deduped by `propertyId` (default 100). |
| `stars`, `reviewScoreMin`, `reviewScoreMax`, `priceMin`, `priceMax`, `name`, `freeCancellation`, `breakfastIncluded`, `paymentOptions`, `facilitiesAny`, `facilitiesAll`, `accommodationTypes`, `areaIds`, `landmarkIds`, `affordableCategory`, `bedrooms`, `familyFacilities`, `hostLevel`, `characteristics`, `tripPurpose`, `curatedCollections`, `deals`, `hotelChainIds`, `productType`, `bookingDuration` | no | Filters. Every one of these was live-verified to actually narrow results on Agoda's own API before being exposed here — see the input schema for value ranges and sample ids. |

#### Sort fields

`sortField` accepts: `Ranking` (default, server "best match"), `Price`, `StarRating`,
`AllGuestsReviewScore`, `GroupsReviewScore`, `FamiliesWithYoungReviewScore`,
`FamiliesWithTeenReviewScore`, `SoloTravllersReviewScore`, `CouplesReviewScore`,
`BusinessTravellerReviewScore`, `ReviewCount`, `ReviewAndPrice`, `InsiderDeal`,
`SecretDeal`, `PackageDeal`, `DistanceFromLandmark` (needs `sortLandmarkId` to honour
`sortOrder`). `Price` and `StarRating` are strictly monotone both directions.
`ReviewAndPrice`/`InsiderDeal`/`SecretDeal`/`PackageDeal` ignore `sortOrder`
server-side (a blended deal/value ranking either way). Left out on purpose because
Agoda's own research found them inert (aliased to the default order) or too weakly
verified to expose: `Distance`, `Personalize`, `CuratedCollectionRank`, `NoSorting`,
`ASD`, `HotelId`, `DistanceFromCityCenter`.

### Output

One dataset row per unique hotel:

```json
{
    "propertyId": 14654101,
    "name": "Solaria Nishitetsu Hotel Bangkok",
    "starRating": 4,
    "accommodationType": "Hotel",
    "city": "Bangkok",
    "area": "Sukhumvit",
    "lat": 13.73682689666748,
    "lon": 100.56027221679688,
    "reviewScore": 9.2,
    "reviewCount": 15912,
    "currency": "USD",
    "priceNightExclusive": 131.02,
    "priceNightAllInclusive": null,
    "available": true
}
```

### Pagination and dedupe

This Actor paginates Agoda's `hotels/search` internally (100 hotels per page, Agoda's
own max) until `maxResults` unique hotels are collected or the upstream runs dry.
Agoda's own deep pagination is **not stable**: adjacent pages of a large destination can
repeat or skip hotels (verified: 57 pages of 100 for one city returned 5671 rows but
only 4504 unique `propertyId`s). This Actor deduplicates by `propertyId` as a courtesy —
duplicate hotels are silently dropped rather than billed or pushed twice — but very deep
pagination of a huge destination can still undercount the true number of listings; for
full coverage of a huge city, narrow with `areaIds`/`stars`/`priceMin`/`priceMax` first.

### Pricing / Cost estimation

Billed **pay-per-event**: one `hotel` event per unique hotel row pushed, plus a flat
`apify-actor-start` event per run. Rows cut off by `maxResults` or a run's spending
limit are not billed beyond that limit.

### Known limitations

- Deep paging of a very large destination is inherently unstable on Agoda's own API
  (see "Pagination and dedupe" above); this Actor mitigates it with dedupe but cannot
  fully fix it upstream.
- `searchInfo` totals jitter and `priceMin`/`priceMax` can leave Agoda's own reported
  total stale — this Actor counts only the actual hotel rows it returns.
- Only Agoda's `city` search type is exposed here (destination/cityId in, hotels out).
  Area/region/radius/bounding-box/landmark search and non-search endpoints (property
  detail, rooms, reviews, flights) live in the sibling
  [Agoda All-in-One API](https://github.com/RomySaputraSihananda/agoda-all-in-one-api).
- Sort fields and filters not listed above were checked in the sibling project's
  research and found inert (accepted but ignored) or unverified on Agoda's own API —
  they are deliberately not exposed here as if they worked.

### FAQ, disclaimers, and support

This is an **unofficial** Actor, not affiliated with or endorsed by Agoda. It reads
only data that Agoda's own Android app shows without an account. Use responsibly and
in line with Agoda's Terms of Service and applicable law.

Found an issue or need a custom field? Use the **Issues** tab on this Actor's page.

# Actor input Schema

## `destination` (type: `string`):

Free-text place name, e.g. "Bangkok". Resolved to a cityId via Agoda's own autocomplete. Either this or cityId is required.

## `cityId` (type: `integer`):

Agoda city id, used directly instead of resolving "destination" (skips the extra autocomplete call). Either this or destination is required. Example known-working id: 9395 (Bangkok).

## `checkin` (type: `string`):

Check-in date, format YYYY-MM-DD. Required.

## `checkout` (type: `string`):

Check-out date, format YYYY-MM-DD. If given, overrides "los" (los is computed as checkout-checkin).

## `los` (type: `integer`):

Length of stay in nights, 1-30. Ignored if checkout is given. Defaults to 1 night.

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

Adults per room.

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

Number of rooms.

## `children` (type: `integer`):

Children per room.

## `childrenAges` (type: `array`):

Ages of each child (0-17), one per entry. Padded with age 8 / truncated to match "children" if the count differs.

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

ISO currency code for prices, e.g. USD, THB, EUR.

## `locale` (type: `string`):

Response language as an Agoda locale, e.g. th-th, ja-jp, zh-cn, en-us (default).

## `sortField` (type: `string`):

Sort field (default Ranking = server "best match"). Only fields verified to actually reorder results are offered; see README for per-field notes (e.g. Price/StarRating are strictly monotone, ReviewAndPrice/InsiderDeal/SecretDeal/PackageDeal ignore sortOrder, DistanceFromLandmark needs sortLandmarkId).

## `sortOrder` (type: `string`):

Sort direction. Ignored by some sortField values (see sortField description).

## `sortLandmarkId` (type: `integer`):

Landmark id to sort by distance from. Only affects sortField=DistanceFromLandmark.

## `maxResults` (type: `integer`):

Stop after this many unique hotels (deduped by propertyId). Paginates hotels/search internally up to this many, or until the upstream runs out.

## `stars` (type: `array`):

Star-rating buckets to include (1-5; 1 means <2 stars), OR'd together.

## `reviewScoreMin` (type: `number`):

Minimum guest review score, 0-10 scale.

## `reviewScoreMax` (type: `number`):

Maximum guest review score, 0-10 scale.

## `priceMin` (type: `number`):

Minimum per-night price in "currency".

## `priceMax` (type: `number`):

Maximum per-night price in "currency".

## `name` (type: `string`):

Filter by hotel name (server-side match), e.g. "Hilton".

## `freeCancellation` (type: `boolean`):

Only hotels with a free-cancellation rate available.

## `breakfastIncluded` (type: `boolean`):

Only hotels with a breakfast-included room offer.

## `paymentOptions` (type: `array`):

Payment-option ids, OR'd together (84640 pay now, 49499 free cancellation, 52770 book now pay later, 56649 pay at hotel, 80031 no credit card needed).

## `facilitiesAny` (type: `array`):

Hotel-facility ids, matches hotels with ANY of them (OR; sample: 93 pool, 92 gym, 90 internet, 80 car park, 17 airport transfer, 116 24h front desk).

## `facilitiesAll` (type: `array`):

Hotel-facility ids, matches hotels with ALL of them (AND).

## `accommodationTypes` (type: `array`):

Accommodation-type ids (sample: 34 Hotel, 29 Apartment/Flat, 33 Hostel, 120 Serviced apartment, 131 Entire House, 32 Guesthouse/B\&B).

## `areaIds` (type: `array`):

Restrict results to these area ids within the searched destination.

## `landmarkIds` (type: `array`):

Restrict results to hotels near these landmark ids.

## `affordableCategory` (type: `array`):

Affordable-category ids (1 Budget, 2 Luxury).

## `bedrooms` (type: `array`):

Number-of-bedrooms buckets (1, 2, 3=3+).

## `familyFacilities` (type: `array`):

Family-facility ids.

## `hostLevel` (type: `array`):

Host-level ids.

## `characteristics` (type: `array`):

Property "characteristic" ids (sample: 1 Backpacker Favorite, 9 Transit, 10 Value For Money, 13 Shopping, 16 Sightseeing).

## `tripPurpose` (type: `array`):

Trip-purpose ids.

## `curatedCollections` (type: `array`):

Curated-collection ids.

## `deals` (type: `array`):

Deal ids (sample: 81337 secret deals, 81485 50%+ discount, 119520 2X AgodaCash, 105046 AgodaVIP Deals).

## `hotelChainIds` (type: `array`):

Hotel-chain ids (sample: 3 Accor).

## `productType` (type: `array`):

Product-type ids (-1 all, 1 hotels, 2 homes).

## `bookingDuration` (type: `string`):

Booking-duration type.

## Actor input object example

```json
{
  "destination": "Bangkok",
  "checkin": "2026-11-10",
  "los": 1,
  "adults": 2,
  "rooms": 1,
  "children": 0,
  "currency": "USD",
  "locale": "en-us",
  "sortField": "Ranking",
  "sortOrder": "Desc",
  "maxResults": 100
}
```

# Actor output Schema

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

No description

# 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 = {
    "destination": "Bangkok",
    "checkin": "2026-11-10"
};

// Run the Actor and wait for it to finish
const run = await client.actor("romy/agoda-hotel-search-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 = {
    "destination": "Bangkok",
    "checkin": "2026-11-10",
}

# Run the Actor and wait for it to finish
run = client.actor("romy/agoda-hotel-search-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 '{
  "destination": "Bangkok",
  "checkin": "2026-11-10"
}' |
apify call romy/agoda-hotel-search-scraper --silent --output-dataset

```

## MCP server setup

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