kestrel actors docs

kestrel actors › Guest & customer reviews

Despegar Hotel Ratings Scraper — Guest Scores & Summary

Scrape despegar hotel ratings from any hotel page on Latin America's largest online travel agency: the 0-10 overall guest score, the number of reviews behind it, six category scores, the AI-written hotel review summary Despegar publishes, and the individual comments the page shows. One request per hotel, no browser, no login, no API key. If you have been looking for despegar hotel reviews, hotel guest ratings or guest scores for the LatAm market in a machine-readable form, this is the fastest path to them.

Run Despegar Hotel Ratings Scraper on Apify →

Despegar hotel ratings pricing: what one row costs

EventWhat it isPriceCharged for
hotelHotel rating row$0.004One Despegar hotel: the 0-10 guest rating with the review count it is based on, the six category scores (service, staff, location, Wi-Fi, cleanliness, value), Despegar's own AI-written summary of what guests say, stars, city, country and coordinates. The individual comments (at most four per hotel, whatever the review count says), hotels with no rating, unknown ids, hotels dropped by minRating and status rows are all free.

Despegar hotel ratings input reference

Every field of Despegar Hotel Ratings, straight from the actor's input schema.

FieldTypeDefaultWhat it does
startUrlsarray[]Despegar hotel pages, e.g. https://www.despegar.com.ar/hoteles/h-265543/riu-cancun — any country domain works (.com, .com.ar, .com.mx, .com.co, .cl, .com.pe, us.despegar.com/hotels/…) and each URL is fetched on the domain you give it, so you can mix countries in one run. The slug does not matter: Despegar redirects any slug to the canonical one.
hotelIdsarray[]Despegar's numeric hotel ids, e.g. 265543 — the number in /h-<id>/ and what an earlier run's hotel_id gives you. Ids are fetched on the country domain chosen below. This is the cheapest input: no lookup, one request per hotel.
countrystring (enum)"com"Which Despegar domain to read hotel ids from. Every domain publishes the same hotel, the same 0-10 rating, the same review count and the same comments — the domain decides the language of the AI summary, the category labels and the review dates, and the currency of the page. "com" lets Despegar pick by the proxy's exit country. Brazil (decolar.com) is listed for completeness but refused every request we made, so avoid it. One of: com, us, ar, mx, co, cl, pe, uy, ec, bo, py, pa, cr, gt, br.
localestring (enum)"auto"Which language you want the AI summary, the category labels and the review dates in. Despegar has no language switch of its own — Accept-Language and ?language= are both ignored — so the language is the domain: "en" reads us.despegar.com, "es" reads despegar.com.ar. Only used when the country above is left at "com"; an explicit country always wins. One of: auto, es, en.
includeCommentsbooleantrueAlso emit the individual guest comments the hotel page publishes — at most four per hotel, whatever the review count says. They are free rows: a hotel costs the same with or without them. Each comment carries its 0-10 score, the good half, the bad half, the month it was written, the traveller type and the reviewer's country.
minRatingnumber0Despegar scores hotels 0-10 (every row also carries the same score on the 0-5 scale as rating_5). 0 = no floor. 8 keeps only the well-rated ones. Hotels below the floor are dropped before billing and never charged; hotels with no rating at all are reported as no_reviews and are always free. Range 0-10.
sessionsinteger2How many proxy sessions (egress IPs) run in parallel. More is faster; each is paced separately and each keeps its own DataDome cookie, which is what makes a session work at all. Range 1-16.
perIpnumber0.5Pace for each session. Measured on Despegar: one session served four hotel pages at 1 req/s and was then refused for the rest of the minute, so the default is deliberately slow. 0.3-0.5 is comfortable; above 1 expect blocks and retries, which cost residential traffic without going faster. Range 0.1-3.
proxyConfigurationobject{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}Apify Proxy with the RESIDENTIAL group is required and is the default: Despegar's DataDome gate refuses every datacenter range outright (403 on every attempt, both TLS profiles), and only residential IPs with a Chrome TLS fingerprint are served. Keep the default.

Example input

{
  "hotelIds": ["265543", "4382832", "6599128"],
  "country": "mx",
  "includeComments": true,
  "minRating": 8,
  "sessions": 2,
  "perIp": 0.5,
  "proxyConfiguration": {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}
}

Despegar hotel ratings output fields

One row per hotel with its guest rating, category scores and Despegar's own AI summary (charged), plus the up-to-four published comments and a status row per target (both free).

Dataset views in the Apify Console: Overview, Hotel ratings, Category scores, Comments, Map, Status.

FieldTypeWhat it holds
typestringhotel | review | status
targetstringThe input value (URL or hotel id) this row came from
hotel_idstringDespegar's numeric hotel id (the number in /h-<id>/); the same id on every Despegar country domain
hotel_namestringHotel name as the chosen Despegar site writes it
hotel_urlstringCanonical hotel page URL on the domain that was read
citystringCity, from the location line under the hotel name (hotel rows)
countrystringCountry of the hotel, in the page's language (hotel rows)
addressstringStreet address as printed in the map section (hotel rows)
latitudenumberLatitude of the hotel marker (hotel rows)
longitudenumberLongitude of the hotel marker (hotel rows)
starsintegerStar rating, counted from the stars printed above the hotel name (hotel rows)
ratingnumberOverall guest rating on Despegar's 0-10 scale, e.g. 8.4
rating_scaleintegerThe scale the rating is on: always 10 (hotel rows)
rating_5numberThe same score converted to the 0-5 star scale, e.g. 8.4 -> 4.2
rating_labelstringDespegar's word for the score, e.g. "Muy bueno" / "Very good" (hotel rows)
review_countintegerHow many guest reviews the rating is based on, as Despegar counts them (e.g. 4511) — not how many this actor can deliver (hotel rows)
reviews_shownintegerHow many individual comments the page actually publishes: at most four (hotel rows)
score_servicenumberCategory score 0-10: services and installations (hotel rows)
score_staffnumberCategory score 0-10: accommodation staff (hotel rows)
score_locationnumberCategory score 0-10: location (hotel rows)
score_internetnumberCategory score 0-10: internet / Wi-Fi (hotel rows)
score_cleanlinessnumberCategory score 0-10: cleaning (hotel rows)
score_valuenumberCategory score 0-10: price/quality (hotel rows)
category_scoresobjectThe same six scores keyed by Despegar's own codes: service, servicePersonal, location, internetAccessAndQuality, cleaning, qualityprice (hotel rows)
summarystringDespegar's own AI-written summary of what guests say about the hotel, generated by Despegar from all its reviews and published on the page — their text, not ours (hotel rows)
verified_notestringDespegar's provenance note for the sample, e.g. "Clientes verificados por Grupo Despegar." (hotel rows)
providersarrayWhich review providers the published comments come from; DESPEGAR on every hotel we have seen (hotel rows)
trip_typesarrayTraveller profiles Despegar offers to filter the comments by: couple, friends, singles, family (hotel rows)
page_languagestringLanguage the domain served, e.g. es or en (hotel rows)
page_countrystringCountry code of the Despegar site that was read, e.g. AR (hotel rows)
review_idstringDespegar's id for the comment (review rows)
review_datestringThe month the guest wrote the comment, in the page's language, e.g. "Agosto 2023" — Despegar publishes no day (review rows)
review_monthstringThe same date normalised to YYYY-MM (review rows)
textstringThe comment: the good half and the bad half joined; Despegar reviews have no title (review rows)
goodstringWhat the guest liked (review rows)
badstringWhat the guest disliked; absent when they only wrote praise (review rows)
reviewerstringGuest's first name, when they published one (review rows)
reviewer_countrystringGuest's country, when published (review rows)
reviewer_country_codestringTwo-letter code for that country (review rows)
trip_typestringWho was travelling: couple | friends | singles | family (review rows)
trip_type_labelstringThe same, as the page words it, e.g. "En familia" (review rows)
languagestringLanguage the comment was written in (review rows)
providerstringWhich provider supplied the comment, e.g. DESPEGAR (review rows)
provider_labelstringDespegar's badge for that provider, e.g. "Huésped verificado" (review rows)
helpful_votesintegerHow many readers marked the comment useful (review rows)
statusstringok | no_reviews | not_found | filtered | duplicate | blocked | limited | error (status rows)
hotelsinteger1 when a hotel row was delivered and charged for this target (status rows)
commentsintegerHow many published comments were delivered for this target, free (status rows)
filteredinteger1 when minRating dropped this hotel before billing (status rows)
duplicatesinteger1 when this target is the same hotel as an earlier one (status rows)
errorstringWhy a target produced nothing (status rows)
fetched_atstringUTC timestamp of the request

Example row from a real run

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

{
  "type": "hotel",
  "target": "265543",
  "hotel_id": "265543",
  "hotel_name": "Riu Cancun",
  "hotel_url": "https://www.despegar.com.ar/hoteles/h-265543/riu-cancun-cancun",
  "city": "Cancún",
  "country": "México",
  "address": "Blvd. Kukulcan, Km 9, Manzana 50, Lote 5, Zona Hotelera Cancún - Quintana Roo",
  "latitude": 21.1370565,
  "longitude": -86.7485229,
  "stars": 5,
  "rating": 8.4,
  "rating_scale": 10,
  "rating_5": 4.2,
  "rating_label": "Muy bueno",
  "review_count": 4511,
  "reviews_shown": 4,
  "score_service": 8.3,
  "score_staff": 9.1,
  "score_location": 9.6,
  "score_internet": 8.9,
  "score_cleanliness": 8.9,
  "score_value": 8.6,
  "category_scores": {"service": 8.3, "servicePersonal": 9.1, "location": 9.6, "internetAccessAndQuality": 8.9, "cleaning": 8.9, "qualityprice": 8.6},
  "summary": "El Riu Cancún es un lugar increíble para relajarse y disfrutar…",
  "verified_note": "Clientes verificados por Grupo Despegar.",
  "providers": ["DESPEGAR"],
  "trip_types": ["couple", "friends", "singles", "family"],
  "page_language": "es",
  "page_country": "AR",
  "fetched_at": "2026-08-29T18:20:11+00:00"
}
{
  "type": "review",
  "review_id": "661ec3c8fe92b10bfdade9ca",
  "hotel_id": "265543",
  "hotel_name": "Riu Cancun",
  "rating": 9.7,
  "rating_5": 4.85,
  "review_date": "Abril 2024",
  "review_month": "2024-04",
  "text": "Hospitalidad de parte de todo el personal… — No alcance a darme cuenta que faltara algo.",
  "good": "Hospitalidad de parte de todo el personal…",
  "bad": "No alcance a darme cuenta que faltara algo.",
  "reviewer": "Lisbeth",
  "reviewer_country": "Chile",
  "reviewer_country_code": "CL",
  "trip_type": "couple",
  "trip_type_label": "En pareja",
  "language": "es",
  "provider": "DESPEGAR",
  "provider_label": "Huésped verificado",
  "helpful_votes": 25
}

Despegar hotel ratings in Python, JavaScript and curl

Python

from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("kestrel/despegar-hotel-ratings").call(run_input={
    "hotelIds": ["265543", "4382832"], "country": "ar", "minRating": 8})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "hotel":
        print(row["hotel_name"], row["rating"], row["review_count"], row["score_value"])

JavaScript (Node)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('kestrel/despegar-hotel-ratings').call({
    startUrls: ['https://www.despegar.com.ar/hoteles/h-265543/riu-cancun'], includeComments: true });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.type === 'hotel'));

curl

curl -X POST "https://api.apify.com/v2/acts/kestrel~despegar-hotel-ratings/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"hotelIds":["265543"],"country":"us","includeComments":true}'

The same three calls are runnable files in the examples repository: examples/despegar-hotel-ratings.py|.js|.sh.

Limits, and what this actor will never do

  • Four comments per hotel, maximum. Not a setting, not a paging bug: the ceiling of the public page. reviews_shown tells you the exact number every time.
  • No day-level review dates. The source publishes month and year only; review_month gives you YYYY-MM.
  • No management replies, no photos. They are not on the page.
  • No search. Give the actor hotels; it does not crawl destinations. That keeps costs predictable on a residential proxy.
  • No Brazilian domain. decolar.com is hard-blocked, as described above.
  • Residential proxy required. Datacenter ranges are refused by the source, so a run without residential proxy will produce blocked rows. It is the default in the input form; leave it alone.

Everything above was measured on 2026-08-29 against the live site through Apify's residential proxy, and the actor's fixtures are the captured pages themselves, so the next time the source changes shape the tests fail before your run does.

FAQ

Why only four comments per hotel?

Because that is all the page publishes. review_count can say 4,511 while reviews_shown says 4. The site's own tracking call reports total_comments: 4, and a headed browser session found no endpoint that returns more — no XHR, no "see all reviews" route, no provider feed. Adding dates to the URL (the booking funnel) changes nothing: still four, still one provider. We would rather sell you the rating honestly than a review scraper that quietly returns four rows.

Is review_count the number of rows I get?

No, and this is the single most important line in this readme. review_count is Despegar's own total; reviews_shown is how many comments came back (0-4). You are billed once per hotel either way — the comments are free.

Does the country site change the numbers?

No. We fetched the same hotel on nine domains: identical id, identical 0-10 score, identical review count, identical four comments. What changes is the language of the AI summary, the category labels and the review dates, plus the page currency. Pick us for English, any LatAm code for Spanish.

Can I get Brazilian hotel ratings?

Brazil is served by decolar.com, and it refused every request we made (six attempts across three residential sessions, all DataDome 403). The domain is in the input list for completeness, but expect blocked status rows. Brazilian hotels are of course covered by every other site — the id is global.

What exactly is the AI review summary?

An ai review summary written by Despegar, not by us and not by an LLM we run. It is one paragraph distilling every review a hotel has, printed above the comments. It arrives in the summary field verbatim.

What does a hotel with no reviews look like?

Its page simply has no ratings module. You get a status row with no_reviews, no hotel row, and no charge. That is an honest empty answer, and it is never confused with a block: a block is an HTTP 403 with a DataDome body, and it is reported as blocked with the reason in error.

How much does a run cost?

$0.004 per hotel row delivered, plus Apify platform usage (compute and residential proxy traffic; a hotel page is roughly 0.45 MB). Comments, status rows, unknown ids, unrated hotels and hotels dropped by minRating are all free. Ten thousand hotels is $40 of events.

Is scraping this legal?

You are reading a public page that requires no login, and taking facts from it — scores, counts, dates — which are not themselves copyrightable in most jurisdictions. That is generally lawful, and hiQ v. LinkedIn is the usual reference for public data. The legal caveats are real, though: the site's terms of use, the personal data in a reviewer's name and country (GDPR/LGPD apply if you store it), and the AI summary, which is Despegar's own creative text — quote it with attribution rather than republishing it as your own. Ask your own counsel before you build a product on it.

Can I use it from n8n, Make.com or an AI agent?

Yes. The actor is a standard Apify actor, so it appears in the Apify nodes for n8n and Make.com, and through Apify's MCP server it can be called directly by an AI agent or by Claude. The dataset is available as JSON, CSV, Excel or an API URL, and the run summary is a single record in the key-value store under SUMMARY.

What happens when I hit my spending limit?

Nothing is delivered that was not paid for. Every hotel is charged before its row is pushed; if the platform refuses the charge, the row is not pushed and the target is marked limited. Charged always equals delivered — that invariant is covered by the actor's own test suite across every input mode and budget.

Can I fetch despegar hotel ratings by id, with no API key?

Yes — that is the normal way to run it. There is no public API here, so despegar hotel ratings by id is exactly what this actor does: you pass hotelIds, it reads the page. Using despegar without an api key is the point; the source publishes no key-based endpoint at all, and none is needed.

How do I find hotel ids in the first place?

Any hotel URL contains one. Beyond that, the site's sitemaps in robots.txt all 404, so harvesting means reading city and home pages, which inline a dozen or two /h-<id>/ links each. If you already have a list of properties, the fastest route is to search the site once by hand and keep the ids: they never change and they work on every country domain.

How to use Despegar Hotel Ratings Scraper

Run Despegar Hotel Ratings 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/despegar-hotel-ratings