kestrel actors docs

kestrel actors › Guest & customer reviews

Trip.com Reviews Scraper — Hotel Guest Reviews & Ratings

A trip.com reviews scraper that returns every guest review a hotel has, as structured rows: trip.com ratings on both the 0–10 and 5-star scales, the rating word, the four sub-scores (location, cleanliness, service, amenities), the review text in the language it was written in, posting and check-in dates, room type, traveler type, reviewer name and country, photos, and the hotel's public reply. Because Trip.com is Ctrip's international brand, the same rows are ctrip reviews — the Chinese-language corpus that no other OTA carries — alongside the Expedia-group reviews Trip.com aggregates. It turns trip.com hotel reviews into hotel review data you can query: a hotel review scraper built for bulk work, not one page at a time.

Run Trip.com Reviews Scraper on Apify →

Trip.com reviews scraper pricing: what one row costs

EventWhat it isPriceCharged for
reviewReview row$0.004One guest review: rating on both the 0-10 and 5-star scales with four sub-scores, review text in its original language, stay date, room, travel type, reviewer country and the hotel's reply. Properties with no reviews are free.

$0.004 per review row. Hotel rows, status rows, filtered reviews, hotels with no reviews, unknown ids and failed hotels are free. A 95-review property costs $0.38 in full; the same property as a daily complaints feed costs a fraction of a cent per day. Apify's platform usage (a few seconds of compute per hotel) is separate and small: the verified runs below used well under a cent each.

Bulk hotel reviews at scale: 1,000 hotels × 200 most-recent reviews = 200,000 rows = $800, delivered in an afternoon with 16 sessions. The pocket's leading actor charges the same per review; the difference is what you get per row and what you never pay for.

Trip.com reviews scraper input reference

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

FieldTypeDefaultWhat it does
startUrlsarray[]Trip.com hotel pages, e.g. https://www.trip.com/hotels/lisbon-hotel-detail-2561632/valverde-hotel/ — the numeric id sits in the URL, so no page has to be read. Any trip.com country subdomain works (us., uk., …).
hotelIdsarray[]Trip.com's numeric hotel ids, e.g. 2561632 — the number after hotel-detail- in any hotel URL, and what an earlier run's hotel_id gives you.
maxReviewsPerHotelinteger2000 = every review the hotel has (Trip.com pages them 100 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.
languagesarray[]Leave empty for every language. Otherwise the languages to keep, by name (English, Chinese, Japanese, Korean, German, French, Spanish, …) or Trip.com language id. Trip.com filters server-side, so the reviews you skip are never fetched or charged. Trip.com carries a lot of Chinese-language reviews from Ctrip — this is how you keep or drop them.
maxRatingnumber00 = keep every review. 1-10 on Trip.com's scale (6 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.
requireTextbooleanfalseDeliver and pay for only the reviews that actually say something (Trip.com reviews almost always do; this guards the rest).
localestring"en-US"Trip.com locale for the request, e.g. en-US, en-GB, ja-JP, de-DE. It sets the language of Trip.com's labels (rating words, travel types); reviews always come back in the language they were written in.
includeHotelRowbooleantrueAlso emit one row per hotel with its id, name, stars, address, overall and sub-scores, review count and the languages its reviews come in. 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. Trip.com tolerated bursts of 20 in testing; 1/s per IP is a safe default. Range 0.1-3.
proxyConfigurationobject{"useApifyProxy": true}Apify Proxy is required so runs rotate IPs. The default datacenter group works for Trip.com.

Example input

{
  "startUrls": ["https://www.trip.com/hotels/lisbon-hotel-detail-2561632/valverde-hotel/"],
  "maxReviewsPerHotel": 0,
  "reviewsSort": "most_recent",
  "maxRating": 6,
  "requireText": true
}
{
  "hotelIds": ["2561632", "100632153", "3064303"],
  "maxReviewsPerHotel": 0,
  "languages": ["English", "Chinese"],
  "reviewsSort": "most_relevant"
}

Trip.com reviews scraper output fields

One row per guest review (charged), plus a free hotel context row and a free status row per property.

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

FieldTypeWhat it holds
typestringRow type: review, hotel or status.
hotel_idstringTrip.com's numeric hotel id.
hotel_namestringHotel name, from the hotel page (hotel rows and, when the page was read, review rows).
urlstringThe Trip.com hotel page, when the run was given one.
localestringTrip.com locale the request used.
starsintegerHotel rows: star class.
addressstringHotel rows: street address.
citystringHotel rows: city.
countrystringHotel rows: country.
review_countintegerHotel rows: how many reviews Trip.com shows for the property.
languagesarrayHotel rows: the languages the property's reviews come in, with Trip.com's id and count for each.
travel_typesarrayHotel rows: traveler types with review counts.
reviews_fetchedintegerHotel rows: how many reviews were taken for the property.
review_idstringTrip.com's review id (stable; use it to dedupe scheduled runs).
ratingnumberOverall score on Trip.com's 0-10 scale (hotel rows: the property's overall score).
rating_5numberThe same score on the 5-star scale.
rating_textstringTrip.com's word for the score: Outstanding, Amazing, Great, Very good, Good…
rating_locationnumberLocation sub-score (0-10).
rating_facilitynumberAmenities sub-score (0-10).
rating_servicenumberService sub-score (0-10).
rating_roomnumberCleanliness sub-score (0-10).
textstringThe review, in the language it was written in.
languagestringLanguage code of the review text (en, zh, ja, fr…).
recommendbooleanWhether the guest recommends the hotel.
review_datestringWhen the review was posted (ISO 8601).
check_instringCheck-in date of the stay (YYYY-MM-DD).
room_typestringRoom type booked.
room_idstringTrip.com's room type id.
travel_typestringCouple, Family, Business traveler, Solo traveler, Traveling with friends, Booked for others, Other.
travel_type_idintegerTrip.com's id for the travel type.
reviewer_namestringReviewer's display name.
reviewer_countrystringReviewer's country or region.
reviewer_country_codestringISO country code of the reviewer.
reviewer_reviewsintegerHow many reviews the reviewer has written on Trip.com.
reviewer_levelstringTrip.com reviewer grade (Rising review star, Review Specialist…).
helpful_votesintegerHelpful votes the review received.
imagesarrayPhoto URLs attached to the review.
sourcestringWhere the review came from: Trip.com, ctrip, Expedia Group verified review, Hotels.com verified review.
source_codeintegerTrip.com's numeric source code.
responsestringThe hotel's public reply, when it replied.
response_datestringWhen the hotel replied.
targetstringStatus rows: the input this row is about.
statusstringStatus rows: ok, no_reviews or error.
reviewsintegerStatus rows: review rows delivered for the property.
filteredintegerStatus rows: reviews dropped by maxRating / requireText (never charged).
pagesintegerStatus rows: review pages read.
totalintegerStatus rows: how many reviews Trip.com shows for the property.
duplicatesintegerStatus rows: 1 when this input pointed at a property already harvested in the run.
errorstringStatus rows: why the property failed, if it did.
fetched_atstringWhen the row was fetched (UTC, ISO 8601).

Example row from a real run

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

{
  "type": "review",
  "review_id": "2067108455",
  "hotel_id": "2561632",
  "hotel_name": "Hotel Valverde Lisboa - Relais & Chateaux",
  "rating": 9.7,
  "rating_5": 4.85,
  "rating_text": "Amazing",
  "rating_location": 10,
  "rating_facility": 9.5,
  "rating_service": 10,
  "rating_room": 9.5,
  "text": "非常精緻的小型酒店,新裝修的設施很新,床品舒適…",
  "language": "zh",
  "recommend": true,
  "review_date": "2026-08-17T06:13:30",
  "check_in": "2026-08-01",
  "room_type": "Classic Room",
  "travel_type": "Couple",
  "reviewer_name": "Xiaoyufeifeijiejie",
  "reviewer_country": "China",
  "reviewer_country_code": "CN",
  "reviewer_reviews": 10,
  "reviewer_level": "Review Specialist",
  "helpful_votes": 0,
  "images": ["https://ak-d.tripcdn.com/images/…_W_1280_853_R5_Q70.jpg"],
  "source": "ctrip",
  "response": "Dear Guest, Thank you very much for your wonderful review…",
  "response_date": "2026-08-19",
  "url": "https://www.trip.com/hotels/lisbon-hotel-detail-2561632/valverde-hotel/",
  "locale": "en-US",
  "fetched_at": "2026-08-29T04:30:12+00:00"
}

Trip.com reviews scraper in Python, JavaScript and curl

Python

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("kestrel/trip-com-reviews-scraper").call(run_input={
    "hotelIds": ["2561632"],
    "maxReviewsPerHotel": 0,
    "reviewsSort": "lowest_rated",
    "maxRating": 6,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "review":
        print(row["rating"], row["language"], row["travel_type"], row["text"][:80])

JavaScript (Node)

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('kestrel/trip-com-reviews-scraper').call({
    startUrls: ['https://www.trip.com/hotels/lisbon-hotel-detail-2561632/valverde-hotel/'],
    maxReviewsPerHotel: 200,
    languages: ['English'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const reviews = items.filter((r) => r.type === 'review');
console.log(reviews.length, 'reviews; replied to:', reviews.filter((r) => r.response).length);

curl

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

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

Limits and honest notes

  • Trip.com pages 100 reviews per request and reported no throttling at 20 concurrent requests from one IP during testing; the default pace of 1 request/second per session is conservative. Large hotels with several thousand reviews take a minute or two.
  • A refused call from Trip.com looks exactly like a hotel with no reviews — a 200 Success with no review block. The actor detects that shape, retries on a fresh IP with backoff, and reports the hotel as error if every attempt is refused. It never reports a throttled hotel as no_reviews, because a false "no reviews" corrupts your dataset silently while a false error costs one retry.
  • An unknown hotel id is reported as an error on its status row, free, without retrying.
  • The hotel row's name, stars and address come from the hotel page (one extra request per hotel). If that page cannot be read, the row still goes out with the scores from the review endpoint and the name blank, and the reviews are unaffected.
  • Reviews are delivered as written; the actor does not translate. language tells you what each one is in. Trip.com's own translations are not exposed by the endpoint the actor reads.
  • Trip.com counts repeated reviews once (repeatComment), which is why total can be a little above the rows that are actually pageable.

FAQ

Does it need a Trip.com API key or login?

No. It calls the same JSON endpoint Trip.com's own review panel uses, with the request head a browser sends. There is no public trip.com api for reviews, and this is how to get trip.com reviews without api access.

Can I download Trip.com reviews as CSV or Excel?

Yes. Every run writes an Apify dataset; open the Reviews view and export it as CSV, Excel, JSON or XML, or fetch it from the API with ?format=csv.

How do I get only Trip.com negative reviews?

Set maxRating to 6 (or whatever your threshold is), reviewsSort to lowest_rated, and optionally requireText: true. Only the complaints are delivered and billed.

Are Ctrip reviews included?

Yes. Trip.com is Ctrip's international brand and the review endpoint serves ctrip hotel reviews with source: "ctrip", mostly in Chinese. Use languages to keep or drop them.

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

Either. The id is the number after hotel-detail- in any Trip.com hotel URL; a URL is resolved without loading the page.

How many reviews can one hotel return?

All of them — set maxReviewsPerHotel to 0. Trip.com pages 100 at a time; the actor walks the pages until Trip.com runs out and dedupes by review_id.

Are reviews translated, and which languages come back?

Reviews arrive in the language they were written in, tagged in language. The hotel row lists every language the property's reviews come in, with counts, so you can decide what to keep. Multi language hotel reviews are the norm on Trip.com: expect English, Chinese, Japanese, Korean and the local language together.

Does it include the hotel's replies?

Yes: response and response_date, when the hotel replied. Reply rate is a useful management signal in itself.

Can I use it as a general hotel review aggregator?

For Trip.com and what Trip.com aggregates (Ctrip, Expedia, Hotels.com), yes. For a true hotel review aggregator across OTAs, pair it with the Agoda and Airbnb review scrapers below — the rows share the same shape, so one table holds all three.

Can I scrape Trip.com reviews without an API?

That is what this is. No key, no browser automation, no rate-limit babysitting: the actor handles proxies, pacing and retries.

What does bulk work cost?

$0.004 per review, nothing else from the actor. 10,000 reviews is $40. See the cost section above for the platform-usage note.

How to use Trip.com Reviews Scraper

Run Trip.com 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/trip-com-reviews-scraper