# Agoda Hotel Listings Extractor (`kawsar/agoda-hotel-listings-extractor`) Actor

Agoda scraper that pulls hotel listings from any Agoda city search, with nightly prices, star ratings, guest review scores, coordinates and photos, so revenue managers and travel researchers can track rates without checking Agoda by hand.

- **URL**: https://apify.com/kawsar/agoda-hotel-listings-extractor.md
- **Developed by:** [Kawsar](https://apify.com/kawsar) (community)
- **Categories:** Travel, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.99 / 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/platform/actors/running/actors-in-store#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 Listings Extractor: Scrape Agoda Hotel Prices, Ratings and Reviews

Agoda hotel listings extractor that pulls hotel search results from Agoda for any city and date range. Every record carries the nightly price, star rating, guest review score, review count, GPS coordinates, photos, amenities and nearby landmarks. Give it a city name, an Agoda search URL or a numeric Agoda city ID and it pages through the listings until it hits your limit.

This Agoda scraper talks to the same search API the website uses, so the prices match what a traveller would see for your dates, occupancy and currency. No browser, no rendering, just the JSON behind the page.

### Use cases

- **Hotel rate shopping**: track what competitors charge per night across a city and spot when they discount
- **Revenue management**: build a nightly rate history for your own property and its comp set
- **Travel affiliate sites**: fill destination pages with fresh hotel data, review scores and photos
- **Market research**: measure supply by star rating, neighbourhood and property type before entering a market
- **SEO and content teams**: generate "best hotels in X" pages backed by real review scores and prices
- **Price monitoring**: schedule daily runs and alert on rate drops through Apify integrations

### Input

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchTerms` | array | none | City or destination names, one per line. Each name is matched to an Agoda city automatically. |
| `searchUrls` | array | none | Agoda search URLs. Dates, guests and rooms are read from the URL when present. |
| `cityIds` | array | none | Numeric Agoda city IDs for repeat runs where the ID is already known. |
| `checkIn` | string | today + 30 days | Check-in date in YYYY-MM-DD format. |
| `checkOut` | string | check-in + nights | Check-out date in YYYY-MM-DD format. |
| `nights` | integer | 1 | Length of stay used when no check-out date is given. |
| `adults` | integer | 2 | Adults per room, which changes the rates Agoda returns. |
| `children` | integer | 0 | Children in the booking. |
| `childAges` | array | none | Age of each child, required when the children count is above zero. |
| `rooms` | integer | 1 | Number of rooms to price. |
| `currency` | string | USD | Currency for every price field. 20 currencies supported. |
| `language` | string | en-gb | Locale for hotel names, area names and review text. |
| `sortBy` | string | recommended | Recommended, price low to high, price high to low, guest rating or secret deals. |
| `maxResults` | integer | 100 | Maximum hotels collected per destination, capped at 1000. |
| `minStarRating` | integer | 0 | Keep only properties at or above this star rating. |
| `minReviewScore` | integer | 0 | Keep only properties at or above this guest rating out of 10. |
| `minPricePerNight` | integer | 0 | Lowest nightly rate to include. |
| `maxPricePerNight` | integer | 0 | Highest nightly rate to include. 0 means no ceiling. |
| `accommodationTypeIds` | array | none | Agoda accommodation type IDs, for example 34 for Hotel and 29 for Apartment. |
| `facilityIds` | array | none | Agoda facility IDs, for example 93 for Swimming pool and 92 for Gym. |
| `includeUnavailable` | boolean | true | Keep sold out properties for full market coverage. |
| `includeImages` | boolean | true | Collect photo URLs. |
| `maxImages` | integer | 5 | Photos kept per property. |
| `includeReviewSnippets` | boolean | false | Add quoted guest reviews and location topics. |
| `includeLandmarks` | boolean | true | Add nearby transport, attractions and beaches with distances. |
| `keepEmptyFields` | boolean | false | Keep fields Agoda had no value for as nulls instead of leaving them out. |
| `requestTimeoutSecs` | integer | 60 | Timeout for a single request to Agoda. |
| `timeoutSecs` | integer | 600 | Time budget for the whole run. |
| `maxRetries` | integer | 3 | Retries per failed request. |
| `proxyConfiguration` | object | Datacenter (Anywhere) | Proxy type and location for requests. Supports Datacenter, Residential, Special and custom proxies. Optional. |

#### Example input

```json
{
    "searchTerms": ["New York", "Bangkok"],
    "checkIn": "2026-09-19",
    "nights": 2,
    "adults": 2,
    "rooms": 1,
    "currency": "USD",
    "sortBy": "guestRating",
    "maxResults": 200,
    "minStarRating": 3,
    "minReviewScore": 8,
    "maxPricePerNight": 400,
    "includeReviewSnippets": true,
    "proxyConfiguration": { "useApifyProxy": true }
}
```

### What data does this actor extract?

Results land in an Apify dataset, one record per hotel. A trimmed example:

```json
{
    "propertyId": 6950509,
    "hotelName": "Pod Times Square",
    "hotelUrl": "https://www.agoda.com/pod-times-square/hotel/new-york-ny-us.html",
    "propertyTypeName": "Hotel",
    "starRating": 3.0,
    "reviewScore": 8.6,
    "reviewCount": 3184,
    "price": 287.28,
    "priceWithTaxes": 362.99,
    "totalPrice": 287.28,
    "currencyCode": "USD",
    "isAvailable": true,
    "freeCancellation": true,
    "payLater": true,
    "roomsLeft": 5,
    "checkInDate": "2026-09-19",
    "checkOutDate": "2026-09-20",
    "countryName": "United States",
    "cityName": "New York (NY)",
    "cityId": 318,
    "areaName": "Times Square",
    "latitude": 40.7584,
    "longitude": -73.9931,
    "distanceFromCityCenterMeters": 0.0,
    "mainImageUrl": "https://pix8.agoda.net/hotelImages/6950509/-1/07ddf14f1f7c52b335a183348996e549.jpg",
    "highlightedFeatures": ["Free Wi-Fi in all rooms!", "Gym/fitness", "Close to public transportation"],
    "roomFacilities": ["Wi-Fi [free]", "Openable window", "Balcony/terrace", "Desk"],
    "cheapestRoomSizeSqm": 11.0,
    "atmospheres": ["shopping", "sightseeing", "nightlife", "restaurants"],
    "nearbyTransport": [{ "name": "42nd Street Subway Station", "distanceMeters": 180.4 }],
    "isSponsored": false,
    "listingRank": 1,
    "searchCityName": "New York (NY)",
    "totalHotelsInSearch": 483,
    "scrapedAt": "2026-08-10T12:44:02.118342+00:00"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `propertyId` | integer | Agoda property ID, stable across runs and useful as a join key |
| `hotelName` | string | Property name in the selected language |
| `hotelUrl` | string | Direct link to the Agoda property page |
| `propertyTypeName` | string | Hotel, Resort, Apartment, Hostel and similar |
| `starRating` | number | Star rating from 0 to 5, half stars included |
| `reviewScore` | number | Agoda guest review score out of 10 |
| `reviewCount` | integer | Number of Agoda reviews behind the score |
| `reviewSources` | array | Score and review count from every connected review provider |
| `reviewSnippets` | array | Quoted guest reviews with reviewer, country, date and rating |
| `locationTopics` | array | Review snippets grouped by topic, currently location |
| `price` | number | Cheapest nightly rate per room before taxes and fees |
| `priceWithTaxes` | number | Cheapest nightly rate per room including taxes and fees |
| `crossedOutPrice` | number | Original rate shown struck through before the discount |
| `totalPrice` | number | Total stay cost for all rooms and nights before taxes |
| `discountPercent` | number | Discount off the crossed out rate |
| `currencyCode` | string | Currency of every price field |
| `isAvailable` | boolean | Whether rooms are bookable for the searched dates |
| `freeCancellation` | boolean | Whether the cheapest rate cancels free of charge |
| `payAtHotel` | boolean | Whether payment on arrival is offered |
| `roomsLeft` | integer | Rooms remaining at the cheapest rate |
| `countryName` | string | Country the property sits in |
| `cityName` | string | City name as Agoda labels it |
| `cityId` | integer | Agoda city ID, reusable as input for later runs |
| `areaName` | string | Neighbourhood or district |
| `latitude` | number | Latitude in decimal degrees |
| `longitude` | number | Longitude in decimal degrees |
| `distanceFromCityCenterMeters` | number | Straight line distance from the city centre |
| `mainImageUrl` | string | Primary property photo |
| `imageUrls` | array | Additional photo URLs |
| `highlightedFeatures` | array | Features Agoda highlights, such as free Wi-Fi |
| `roomFacilities` | array | Facilities listed for the cheapest room |
| `atmospheres` | array | Neighbourhood tags such as shopping or nightlife |
| `nearbyTransport` | array | Stations and stops with distance in metres |
| `nearbyLandmarks` | array | Attractions with distance in metres |
| `isSponsored` | boolean | Whether the listing is a paid placement |
| `listingRank` | integer | Position in the Agoda result list for the chosen sort |
| `totalHotelsInSearch` | integer | Total properties Agoda reports for the search |
| `scrapedAt` | string | UTC timestamp of collection |

The full field list, including sustainability flags and whole-home room counts, is in the dataset schema.

#### Why some fields are missing from a record

47 fields appear on every hotel. The rest depend on what Agoda knows about that property, so the key is left out rather than written as null. A hotel that is not discounted has no `crossedOutPrice` or `discountPercent`, a sold out hotel has no `price` or `roomsLeft` but does get `soldOutAveragePrice`, and `bedrooms`, `bathrooms` and `beds` only turn up on apartments and whole-home stays. Measured over 135 hotels across New York, Bangkok and Dubai:

| Field | Present |
|-------|---------|
| `nearbyTransport`, `reviewSnippets`, `bookingsToday`, `atmospheres` | 95% to 99% |
| `price`, `priceWithTaxes`, `totalPrice`, `roomsLeft`, `roomFacilities` | 90% |
| `nearbyLandmarks`, `locationTopics` | 77% to 81% |
| `crossedOutPrice`, `discountPercent`, `cheapestRoomSizeSqm` | 72% to 73% |
| `nearbyBeaches` | 33% |
| `goldCircleAwardYear` | 20% |
| `soldOutAveragePrice` | 8% |
| `bedrooms`, `bathrooms`, `beds` | under 2% |

Set `keepEmptyFields` to true if you would rather have every field on every record with nulls in the gaps, which is easier to load into a fixed database schema.

### How it works

1. Every destination name is matched to an Agoda city ID through Agoda's own destination lookup, so "New York" becomes city 318. Search URLs and raw city IDs skip this step.
2. Your dates, occupancy, currency and filters are turned into an Agoda search request. Star rating, review score, price range, property type and facility filters run on Agoda's side, so filtered runs cost less.
3. The actor pages through results, 45 hotels at a time, until it reaches your `maxResults` limit or the end of the listings.
4. Each property is flattened into one dataset record with prices, ratings, location, photos and amenities.
5. Failed requests retry with a backoff, and a bad listing is logged and skipped instead of ending the run.

### FAQ

**How do I scrape hotels for a specific city?**
Type the city name into Destinations, for example "Bangkok" or "Cox's Bazar". You can also paste an Agoda search URL, and the actor reads the city, dates, guests and rooms straight from it.

**Do the prices match what I see on Agoda?**
Prices come from the same search API the website uses, for the dates, occupancy and currency you set. Rates move constantly, so a run captures the market at that moment. Schedule repeat runs if you need a price history.

**How many hotels can one run collect?**
Up to 1000 per destination, and you can queue several destinations in one run. Large cities like Bangkok list thousands of properties, so set `maxResults` to what you actually need.

**Can I filter by star rating, review score or price?**
Yes. Star rating, guest score, price range, accommodation type and facilities are all sent to Agoda as search filters, so the actor only downloads properties that already match.

**Does this actor need a proxy?**
It runs without one, but Apify Proxy is recommended for larger jobs. Datacenter proxies are fast and cheap, and Residential proxies help when a datacenter IP gets rate limited.

**Why does one record have fewer fields than another?**
A field is left out when Agoda has no value for it on that property, so a hotel without a discount carries no `crossedOutPrice`. Turn on `keepEmptyFields` to get nulls in those slots instead. CSV and Excel exports are unaffected either way, since Apify builds the column list from all records.

**Can I get hotel facilities like pool and parking?**
Room level facilities come through in `roomFacilities`, and Agoda's own highlights land in `highlightedFeatures`. The full property amenity list is not part of the search response, it lives on the individual hotel page. You can still filter searches by facility using `facilityIds`.

**Can I get guest reviews too?**
Turn on Include guest review snippets to add short quoted reviews with the reviewer name, country, date and rating, plus location topic snippets.

### Integrations

Connect Agoda Hotel Listings Extractor with other apps and services using [Apify integrations](https://apify.com/integrations). You can integrate with Make, Zapier, Slack, Airbyte, GitHub, Google Sheets, Google Drive, and many more. You can also use [webhooks](https://docs.apify.com/integrations/webhooks) to trigger actions whenever results are available.

Point the Agoda scraper at a city, set your dates, and you get a clean hotel dataset with prices, ratings and reviews ready to load wherever you work.

# Actor input Schema

## `searchTerms` (type: `array`):

City or destination names to search on Agoda, one per line. Each name is resolved to an Agoda city automatically, so 'New York', 'Bangkok' or 'Dubai' all work.

## `searchUrls` (type: `array`):

Paste Agoda search result URLs, one per line. Dates, guests and rooms are read from the URL when present, and anything missing falls back to the settings below.

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

Numeric Agoda city IDs, one per line, for repeat runs where you already know the ID. New York is 318, Bangkok is 9395, Dubai is 2994.

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

Check-in date in YYYY-MM-DD format. Leave empty to search 30 days from today.

## `checkOut` (type: `string`):

Check-out date in YYYY-MM-DD format. Leave empty to use check-in plus the number of nights below.

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

Length of stay used when no check-out date is given.

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

Number of adults per room. Affects which rates Agoda returns.

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

Number of children in the booking.

## `childAges` (type: `array`):

Age of each child, one per line. Required by Agoda whenever the children count is above zero.

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

Number of rooms to price.

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

Currency for all returned prices.

## `language` (type: `string`):

Locale used for hotel names, area names and review snippets.

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

Ordering applied by Agoda before the listings are collected.

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

Upper limit of hotels collected for each destination. Keeps runtime and compute units predictable.

## `minStarRating` (type: `integer`):

Keep only properties at or above this star rating. Set to 0 for no star filter.

## `minReviewScore` (type: `integer`):

Keep only properties scoring at or above this guest rating out of 10. Set to 0 for no review filter.

## `minPricePerNight` (type: `integer`):

Lowest nightly rate to include, in the selected currency. Set to 0 to skip.

## `maxPricePerNight` (type: `integer`):

Highest nightly rate to include, in the selected currency. Set to 0 to skip.

## `accommodationTypeIds` (type: `array`):

Restrict results to Agoda accommodation types, one ID per line. 34 is Hotel, 29 is Apartment, 37 is Resort, 33 is Hostel, 32 is Guesthouse, 28 is Villa.

## `facilityIds` (type: `array`):

Restrict results to properties with these Agoda facilities, one ID per line. 93 is Swimming pool, 92 is Gym, 90 is Internet, 80 is Car park, 24 is Pets allowed, 17 is Airport transfer.

## `includeUnavailable` (type: `boolean`):

Keep properties with no availability for the chosen dates. Useful for full market coverage, turn off for a bookable-only list.

## `includeImages` (type: `boolean`):

Collect photo URLs for each property.

## `maxImages` (type: `integer`):

How many photo URLs to keep per property.

## `includeReviewSnippets` (type: `boolean`):

Add short quoted guest reviews and location topic snippets to each record.

## `includeLandmarks` (type: `boolean`):

Add nearby transport stops, top landmarks and beaches with distances in metres.

## `keepEmptyFields` (type: `boolean`):

By default a field is left out when Agoda has no value for it, for example a crossed out price on a hotel that is not discounted. Turn this on to keep every field with a null instead, which suits loading into a fixed database schema.

## `requestTimeoutSecs` (type: `integer`):

Timeout for a single request to Agoda.

## `timeoutSecs` (type: `integer`):

Overall time budget for the run. The actor stops cleanly and keeps everything collected so far when the budget is spent.

## `maxRetries` (type: `integer`):

How many times to retry a failed Agoda request before moving on.

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

Select proxies to use for requests. Helps avoid IP blocking and rate limits. Datacenter proxies are fastest; Residential proxies are harder to detect.

## Actor input object example

```json
{
  "searchTerms": [
    "New York",
    "Bangkok"
  ],
  "searchUrls": [
    "https://www.agoda.com/en-gb/search?city=318&checkIn=2026-09-19&los=1&rooms=1&adults=2"
  ],
  "cityIds": [
    "318",
    "9395"
  ],
  "checkIn": "2026-09-19",
  "checkOut": "2026-09-20",
  "nights": 1,
  "adults": 2,
  "children": 0,
  "childAges": [
    "7",
    "11"
  ],
  "rooms": 1,
  "currency": "USD",
  "language": "en-gb",
  "sortBy": "recommended",
  "maxResults": 100,
  "minStarRating": 0,
  "minReviewScore": 0,
  "minPricePerNight": 0,
  "maxPricePerNight": 0,
  "accommodationTypeIds": [
    "34",
    "37"
  ],
  "facilityIds": [
    "93",
    "92"
  ],
  "includeUnavailable": true,
  "includeImages": true,
  "maxImages": 5,
  "includeReviewSnippets": false,
  "includeLandmarks": true,
  "keepEmptyFields": false,
  "requestTimeoutSecs": 60,
  "timeoutSecs": 600,
  "maxRetries": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `hotels` (type: `string`):

All scraped hotel records for the run, as dataset items.

## `overview` (type: `string`):

Key columns (hotel, stars, review score, price, area, availability) in the console dataset view.

# 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 = {
    "searchTerms": [
        "New York"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kawsar/agoda-hotel-listings-extractor").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 = {
    "searchTerms": ["New York"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("kawsar/agoda-hotel-listings-extractor").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 '{
  "searchTerms": [
    "New York"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call kawsar/agoda-hotel-listings-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kawsar/agoda-hotel-listings-extractor"
        }
    }
}

```

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/mKLCSScLQ2k0Oja1b/builds/flF3WVXRBvPxyI9hR/openapi.json
