kestrel actors docs

kestrel actors › Guest & customer reviews

Agoda Reviews Scraper — Hotel Guest Reviews & Ratings

An agoda reviews scraper that returns every guest review a property has, as structured rows: agoda ratings on both the 0–10 and 5-star scales, the rating word, title, review text, separate positives and negatives, stay dates and length, room type, reviewer name and country, and the hotel's public reply. It turns agoda hotel reviews into hotel review data you can query — a hotel review scraper built for bulk work rather than one page at a time.

Run Agoda Reviews Scraper on Apify →

Agoda reviews scraper pricing: what one row costs

EventWhat it isPriceCharged for
reviewReview row$0.005One guest review: rating on both the 0-10 and 5-star scales, title, comment, positives and negatives, stay dates, reviewer country and the hotel's reply. Properties with no reviews are free.

Pay per event, one event per delivered review row. Free: hotel rows, status rows, every review removed by maxRating or requireText, properties with no reviews, and failed properties. A property is harvested once per run whether you give its name, its URL, its id, or all three.

A mid-size hotel is a few hundred reviews; a busy hostel can be over a thousand — 1,457 from a single property was verified in testing. maxReviewsPerHotel and the two filters make that a deliberate choice. Verified runs behind this listing cost $0.0002–$0.0026 each in platform compute. Exact per-row pricing is on this page's pricing tab.

Agoda reviews scraper input reference

Every field of Agoda Reviews, straight from the actor's input schema.

FieldTypeDefaultWhat it does
startUrlsarray[]Agoda property pages, e.g. https://www.agoda.com/tivoli-avenida-liberdade-lisboa/hotel/lisbon-pt.html — the run reads the numeric hotel id from the page for you.
hotelIdsarray[]Agoda's numeric ids, e.g. 63820 — the fastest input, and what an earlier run's hotel_id gives you.
hotelNamesarray[]Property names as you would type them into Agoda's search box, e.g. "Park Hyatt Tokyo". The run resolves each to the exact property through Agoda's own autocomplete — no URL or id needed.
maxReviewsPerHotelinteger2000 = every review the property has (Agoda pages them ~200 at a time; large hotels run into the thousands). N = the first N in the order below. The main cost control. Range 0-20000.
reviewsSortstring (enum)"most_recent"Which reviews come first. "Lowest rated" is the fastest way to find complaints; "Most recent" is the one to schedule. One of: most_recent, highest_rated, lowest_rated, most_relevant.
maxRatingnumber00 = keep every review. 1-10 on Agoda's scale (5 is a poor stay) = keep only reviews at or below it, so a complaints feed costs nothing for the happy ones. Filtered reviews are never charged. Range 0-10.
requireTextbooleanfalseMany Agoda reviews are a score with no words. Turn this on to deliver and pay for only the ones that actually say something.
localestring"en-us"Agoda locale for the request, e.g. en-us, es-es, de-de. Every review also carries the language it was written in.
includeHotelRowbooleantrueAlso emit one row per property with its id, name and how many reviews were taken. Never charged.
sessionsinteger4How many proxy sessions (egress IPs) run in parallel. More is faster; each is paced separately. Range 1-16.
perIpnumber1Pace for each session. Agoda tolerates about 1/s per IP; faster causes retries, not speed. Range 0.1-3.
proxyConfigurationobject{"useApifyProxy": true}Apify Proxy is required: Agoda throttles datacentre traffic that is not rotated. The default group works.

Example input

{ "hotelNames": ["Park Hyatt Tokyo"], "maxReviewsPerHotel": 0, "reviewsSort": "lowest_rated", "maxRating": 5, "requireText": true }
{ "startUrls": ["https://www.agoda.com/the-central-house-lisbon-baixa/hotel/lisbon-pt.html"], "maxReviewsPerHotel": 0 }

Agoda reviews scraper output fields

Three row types share one dataset: review (one guest review, charged), hotel (context for a property, free) and status (per property, free).

Dataset views in the Apify Console: Overview, Reviews, Low scores, Run status.

FieldTypeWhat it holds
typestringRow type: review, hotel or status.
hotel_idstringAgoda's numeric property id.
hotel_namestringProperty name, as the hotel signs its own replies.
urlstringThe Agoda property page, when the run was given one.
localestringAgoda locale the request used.
reviews_fetchedintegerHotel rows: how many reviews were taken for the property.
review_idstringAgoda's id for the review.
ratingnumberGuest score on Agoda's 0-10 scale.
rating_5numberThe same score out of five, for comparing with five-star sources.
rating_textstringAgoda's word for the score, e.g. "Exceptional".
titlestringReview headline the guest wrote.
textstringThe review body. Many Agoda reviews are a score with no words: this is then empty.
positivesstringWhat the guest liked, when they filled that field separately.
negativesstringWhat the guest disliked, when they filled that field separately.
original_titlestringUntranslated headline, when Agoda translated the review.
original_textstringUntranslated body, when Agoda translated the review.
languagestringLanguage the review was written in.
translated_tostringLanguage the review was shown in.
review_datestringWhen the review was posted.
review_date_textstringReview date as Agoda prints it.
check_instringStart of the stay being reviewed.
check_outstringEnd of the stay being reviewed.
stay_monthstringMonth and year of the stay, as Agoda prints it.
stay_lengthintegerNights stayed, when Agoda reports it.
room_typestringRoom the guest stayed in, when Agoda reports it.
reviewer_namestringDisplay name of the guest.
reviewer_countrystringCountry the guest booked from.
reviewer_typestringAgoda's label for the reviewer, when present.
group_typestringTraveller group Agoda assigns the stay, when present.
helpful_votesintegerHow many readers marked the review helpful.
unhelpful_votesintegerHow many readers marked it unhelpful.
sourcestringWhich source the review came from — Agoda aggregates partners alongside its own.
provider_idstringNumeric id of that source.
responderstringWho replied, normally the property itself.
responsestringThe property's public reply, when there is one.
response_datestringWhen the property replied.
imagesarrayPhotos the guest attached, when any.
statusstringStatus rows: ok, no_reviews or error.
targetstringStatus rows: the URL or id this job was given.
reviewsintegerStatus rows: review rows delivered.
filteredintegerStatus rows: reviews dropped by maxRating or requireText, never charged.
pagesintegerStatus rows: pages of reviews read.
duplicatesintegerStatus rows: 1 when another input already covered this property.
errorstringStatus rows: why the property failed, null when it did not.
fetched_atstringUTC timestamp when the row was fetched.

Example row from a real run

Taken from the actor's README — this is the shape your dataset holds.

{
  "type": "review", "hotel_id": "63820",
  "hotel_name": "Tivoli Avenida Liberdade", "url": null, "locale": "en-us",
  "review_id": "1059514024", "rating": 10.0, "rating_5": 5.0, "rating_text": "Exceptional",
  "title": "Nice Hotel", "text": "Beautiful hotel in the center!", "positives": null, "negatives": null,
  "original_title": null, "original_text": null, "language": "en", "translated_to": "en",
  "review_date": "2025-12-15T10:54:00+07:00", "review_date_text": "December 15, 2025",
  "check_in": "2025-12-08T00:00:00+07:00", "check_out": "2025-12-14T00:00:00+07:00",
  "stay_month": "December 2025", "stay_length": null, "room_type": null, "group_type": null,
  "reviewer_name": "VARDAN", "reviewer_country": "Mozambique", "reviewer_type": null,
  "helpful_votes": 0, "unhelpful_votes": 0, "images": null,
  "source": "Agoda", "provider_id": "332",
  "responder": "Tivoli Avenida Liberdade", "response": null, "response_date": null
}
{ "type": "hotel", "hotel_id": "63820", "hotel_name": "Tivoli Avenida Liberdade", "url": null, "reviews_fetched": 108, "locale": "en-us" }

Agoda reviews scraper in Python, JavaScript and curl

Python

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("kestrel/agoda-reviews-scraper").call(run_input={
    "hotelNames": ["Park Hyatt Tokyo"], "maxReviewsPerHotel": 0,
    "reviewsSort": "lowest_rated", "maxRating": 5, "requireText": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "review":
        print(row["rating"], row["reviewer_country"], row["text"][:80])

JavaScript (Node)

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('kestrel/agoda-reviews-scraper').call({
    hotelIds: ['63820'], maxReviewsPerHotel: 200, reviewsSort: 'most_recent',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.type === 'review').length, 'reviews');

curl

curl -X POST "https://api.apify.com/v2/acts/kestrel~agoda-reviews-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H 'Content-Type: application/json' \
  -d '{"hotelIds":["63820"],"maxReviewsPerHotel":100}'

The same three calls are runnable files in the examples repository: examples/agoda-reviews-scraper.py|.js|.sh.

Limits and honest notes

  • Agoda rates 0–10, not 1–5. rating is Agoda's own number; rating_5 is the same score halved so you can compare against five-star sources. Do not mix them.
  • Many reviews are a score with no words. That is Agoda, not a parsing gap — requireText drops them if you only want written feedback.
  • positives and negatives are only present when the guest used those fields. Older reviews often put everything in text.
  • A throttled request answers 200 with no reviews at all, rather than an error. The run detects that and retries on a fresh IP, so a busy property is never reported as having none.
  • stay_length, room_type and group_type are frequently null — Agoda only shows them for some reviews.
  • HTTP/2 is required by Agoda's endpoint; over HTTP/1.1 it silently returns nothing. The actor handles this, but it is why a naive script fails.

FAQ

Does it need an Agoda API key or login?

No. There is no public agoda api for reviews to hold a key for. This calls the same endpoint agoda.com's own review widget uses, with no session and no account.

Can I download Agoda reviews as CSV or Excel?

Yes. Every run writes an Apify dataset, exportable to CSV, Excel, JSON or XML from the Console or over the API with ?format=csv. That is the quick path to download agoda reviews for one property or a whole competitor set.

How do I get only Agoda negative reviews?

Set maxRating to your ceiling — 5 on Agoda's 0–10 scale is a poor stay — and reviewsSort to lowest_rated. Add requireText: true so you only pay for reviews with actual words. Everything above the ceiling is dropped before billing.

Do I need the hotel id, or can I use the name?

Either. hotelNames resolves a plain name through Agoda's own autocomplete: Park Hyatt Tokyo became id 910 in testing, and Tivoli Avenida Liberdade became 63820. Use startUrls if you already have the page, or hotelIds if a previous run gave you the number.

How many reviews can one property return?

All of them. Agoda pages about 200 at a time and the run follows the pages, de-duplicating as it goes — 1,457 unique reviews from a single property was verified. maxReviewsPerHotel bounds it when you want a cheaper run.

Are reviews translated, and which languages come back?

Reviews arrive in the language they were written in, tagged in language, and translated_to records what Agoda showed them as. original_text holds the untranslated body when Agoda translated one. Multi language hotel reviews are the normal case here, not an edge case — one property returned 18 languages.

Does it include the hotel's replies?

Yes — responder, response and response_date when the property answered publicly. responder is also how the run recovers the hotel's name, because Agoda ships its property pages with an empty <title>.

Can I use it as a general hotel review aggregator?

For Agoda's corpus, yes — and note that Agoda itself aggregates some partner reviews, which is why each row carries source and provider_id. For a true hotel review aggregator across several OTAs you would run this alongside scrapers for the other sites and join on the property.

Can I scrape Agoda reviews without an API?

That is what this is — agoda reviews without api access, no key to apply for, no approval process. You call an Apify actor and read rows back.

What does bulk work cost?

Bulk hotel reviews are billed per delivered row, so cost scales with data, not time. The two filters and the per-hotel cap cut it directly, because filtered rows are never charged.

How to use Agoda Reviews Scraper

Ready-made runs you can open and start

Each one is a saved input on the Apify Store — open it, press Start, and it runs with the fields already filled in. All 163 across the suite.

Ready-made runWhat it does
Agoda Negative Reviews for Any HotelLowest-scoring reviews with a written complaint, six and below on Agoda scale: what actually goes wrong at a property, and how often.
Multi-Language Hotel Reviews from AgodaAgoda's Asian properties are reviewed in a dozen languages; every row carries the language it was written in, so you can split the corpus by market.
Hotel Reputation Monitoring on AgodaFifty newest reviews for each of three properties by hotel id - small enough to schedule daily and route to Slack when a score drops.
Download Agoda Reviews to CSVFive hundred reviews of one property with scores, titles, positives, negatives, room type and stay dates, exportable as CSV or JSON.
Bulk Hotel Reviews by Agoda Hotel IDEight properties across Asia, Europe and the Gulf in one run, addressed by numeric id: the fastest input and the cheapest per review.
Guest Feedback Data with Text OnlyMany Agoda reviews are a score and nothing else. requireText drops them before billing, so you pay only for feedback that says something.
Agoda Competitor Reviews in BangkokFive Bangkok riverside competitors, a hundred written reviews each: where the comp set is losing points, in the guests own words.
Agoda Ratings: Highest Rated ReviewsThe reviews guests wrote when everything went right, sorted highest first - quotable testimonials with reviewer country and stay dates.
Agoda Hotel Reviews in German (de-de)Ask Agoda in German and the reviews come back for a German-speaking audience, with the original language still recorded on every row.
Agoda Reviews Without API AccessAgoda has no public review API. This is the smallest replacement: one property by name, fifty recent reviews, no key and no partner contract.
Hotel Review Data by Room TypeEvery Agoda review names the room type booked and the stay dates, so complaints can be traced to a room category rather than the property.
Agoda Reviews by Hotel, Most RelevantAgoda's own most-relevant ordering surfaces the reviews future guests actually read - sixty of them is enough to summarise a property.

Run Agoda Reviews Scraper

The actor lives on the Apify Store, where the pricing tab carries the live per-row price and the input form has every field above: apify.com/kestrel/agoda-reviews-scraper