# Agoda Hotel Prices (`superslowsloth/agoda-hotels`) Actor

One search, one flat table: hotel name, id, area, lowest all-in price, star rating, review score and count, and the booking URL - for any Agoda destination and date.

- **URL**: https://apify.com/superslowsloth/agoda-hotels.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** Travel, AI, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 hotel scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Prices

One search in, one flat table out. Give it a destination and a date; it returns
the hotels Agoda would show you, each with its **lowest available all-in price**
in the currency you asked for, its star rating, its review score and review
count, and the URL of the booking page.

Built to be called by an agent or a script: small input, small output, one row
per hotel, no nested objects, no HTML.

### Output

One item per hotel:

| field | meaning |
|---|---|
| `hotel_id` | Agoda's numeric property id, stable across searches |
| `name` | Property name as Agoda displays it |
| `url` | Booking page on agoda.com |
| `area` | Neighbourhood, e.g. `Sukhumvit` |
| `city`, `country` | As Agoda classifies the property |
| `star_rating` | Official star rating, 1-5 |
| `review_score` | Agoda guest score out of 10 |
| `review_count` | Number of guest reviews behind that score |
| `price` | Lowest all-in price, **per room per night**, taxes and fees included |
| `price_excluding_taxes` | The same room before taxes and fees |
| `currency` | Currency the two prices are quoted in |
| `is_available` | Whether anything was bookable for those dates |
| `check_in`, `check_out`, `nights`, `adults`, `rooms` | The search the prices belong to |
| `requested_destination` | The destination string you sent, echoed back |
| `resolved_city`, `resolved_city_id` | The city Agoda actually searched. `null` name when you passed a numeric id |
| `destination_matched` | `false` when Agoda returned a city whose name is not what you asked for |

#### Always check `destination_matched`

Agoda's autocomplete answers nearly any string with a city, so a typo or a bad
input produces a complete, successful, **charged** run about somewhere else.
This actor cannot refuse that outright without also refusing legitimate spelling
variants - Agoda files "Koh Samui" as "Ko Samui" - so instead **every row says
what you asked for and what it got**. When `destination_matched` is `false`,
compare `requested_destination` against `resolved_city` before trusting the
prices. The run log carries a warning for the same case.

### Fields that can be null, and why they are not zero

A price is only ever a number when Agoda quoted one.

- **`price` and `price_excluding_taxes` are `null` for a sold-out property.**
  When nothing is bookable for your dates Agoda still lists the hotel but
  returns no offer at all - there is no price to report. A `0` there would read
  as "free", so this actor never writes one. Sold-out hotels are skipped
  entirely unless you switch on **Include sold-out hotels**.
- **`star_rating`, `review_score` and `review_count` are `null` for a property
  Agoda has no such value for** - typically a new listing with no reviews yet.
  A new hotel is not a hotel that scored 0.
- **`area` is `null`** where Agoda files a property under a city but no
  neighbourhood.

Nothing in the output is inferred, averaged or filled in. Every value came from
the response for the exact search you asked for.

### What it does not do

- **It does not return room-level detail.** One row is one hotel at its cheapest
  bookable rate, not a list of room types.
- **It prices the search you asked for, not the calendar.** Prices are specific
  to the dates, occupancy and currency in the input. Change the dates and the
  prices change; that is the source, not a bug.
- **It has no partner or affiliate access.** It reads the same public search
  Agoda's own website reads, so it sees what a visitor sees - and, like a
  visitor, it does not see private negotiated rates.
- **Destinations resolve to a city, and Agoda will resolve almost anything.**
  An area or landmark ("Chiang Mai Airport") resolves to the city containing it.
  A string that matches no city at all still comes back with *some* city -
  `zzzqqq` resolves to Zschepplin, Germany - so a nonsense destination does not
  fail, it succeeds about the wrong place. **Check `destination_matched` on the
  rows**; see below.

### Proxy

**Use a residential proxy.** Agoda blocks repeated searches from one address and
answers with an HTML challenge page instead of results. The actor treats that -
and any 403, 429 or 5xx - as a temporary refusal, takes a **fresh exit address**
and retries; a permanent error, such as a malformed request, is never retried,
so a hopeless run does not spend your money four times over.
The default proxy setting already asks for the residential group.

### Pricing

- **Actor start** - a small fixed fee per run, so a search that legitimately
  finds nothing still covers its cost.
- **Hotel scraped** - charged once per hotel written to the dataset. A hotel
  that appears on two result pages is charged **once**; Agoda repeats a few
  properties across page boundaries and this actor de-duplicates by property id
  before charging.

Sold-out hotels are not charged unless you asked for them.

### Tips

- `maxItems` counts hotels **delivered**, not hotels looked at, so a sold-out
  property never costs you a row you asked for. Agoda serves 45 per page, so
  asking for 20 usually costs one page and asking for 90 usually costs two.
- Set `currency` to whatever your downstream expects - `THB`, `USD`, `JPY`,
  `SGD`. The conversion is Agoda's, not ours.
- For a repeatable price series, pin `destination` to a numeric city id rather
  than a name, so autocomplete changes cannot move your dataset under you. Take
  the id from `resolved_city_id` on a run you have already checked.

# Actor input Schema

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

A city name such as Bangkok, Phuket or Chiang Mai, or a numeric Agoda city id. Names are resolved through Agoda's own autocomplete, which answers almost any string with some city - a typo can therefore return a real but unrelated place. Every output row carries requested\_destination, resolved\_city and destination\_matched so you can tell the difference.

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

Check-in date as YYYY-MM-DD. Defaults to 30 days from the day the run starts.

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

Length of stay in nights. The check-out date is derived from it.

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

Number of adult guests. Prices are quoted for this occupancy.

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

Number of rooms requested.

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

Number of children. Leave at 0 for an adults-only search.

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

One age per child. Agoda prices some rooms differently by child age; leave empty if you set no children.

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

Three-letter currency code the prices are quoted in, e.g. THB, USD, JPY, SGD.

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

Stop after this many hotels have been delivered. Sold-out properties do not count against it. Agoda serves 45 per page, so a lower number usually costs fewer requests as well as fewer charged items.

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

Off by default. When on, hotels with nothing bookable for those dates are emitted too, with a null price - they are never given a price of 0.

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

Strongly recommended, and residential is what reliably works. Agoda blocks repeated searches from one address and answers with an HTML challenge page.

## Actor input object example

```json
{
  "destination": "Bangkok",
  "nights": 1,
  "adults": 2,
  "rooms": 1,
  "children": 0,
  "childAges": [],
  "currency": "THB",
  "maxItems": 45,
  "includeUnavailable": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `hotels` (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",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/agoda-hotels").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",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/agoda-hotels").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",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call superslowsloth/agoda-hotels --silent --output-dataset

```

## MCP server setup

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

```

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/GZmgI9KLkRFIc0nlO/builds/H8BSGS8nN46Xs7HrQ/openapi.json
