# Trip.com Scraper — Hotel Prices, Rooms, Reviews & Details (`logiover/trip-com-scraper`) Actor

Trip.com (携程 Ctrip international) hotel scraper: the hotels Trip.com lists for any city or area and your dates — nightly price, taxes, total, discounts, free cancellation, ratings, review counts, address, coordinates, photos — plus rooms, policies, amenities, phone and reviews on demand.

- **URL**: https://apify.com/logiover/trip-com-scraper.md
- **Developed by:** [Logiover](https://apify.com/logiover) (community)
- **Categories:** Travel, E-commerce, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Trip.com Scraper — hotel prices, ratings, rooms and reviews from 携程国际

> This Actor is not affiliated with, endorsed by or connected to Trip.com Group Ltd., Ctrip (携程) or Trip.com Travel Singapore Pte. Ltd. It reads hotel information that www.trip.com shows publicly to every visitor, and nothing else.

The **Trip.com scraper** turns Trip.com's hotel search into a dataset. Give it a city, an area, a landmark or a metro station plus your dates, and it returns **the hotels Trip.com lists for those dates, page after page to the end of its list**: nightly price before taxes, total for the stay with taxes and fees, original price and discount, free-cancellation and breakfast flags, cheapest room and bed type, star rating, guest rating with sub-scores, review count, area, coordinates, photos, tags and awards. Switch on hotel pages and you also get the local-language name (上海古象杉丽酒店 next to its English name), phone, email, full street address, transit note, nearby places, policies and the full amenity list. Switch on rooms to add the room types and rates Trip.com returns for your dates (mainly overseas hotels, see the limits); set a review count and the latest guest reviews come along. Export to CSV, Excel, JSON or XML, call it as a **Trip.com API** from your own code, or run it on a schedule. No login, no cookies, no API key.

It is a practical **Trip.com API alternative** for anyone who needs to scrape trip.com hotel data at scale: price monitoring and rate parity, destination market sizing, hotel lead lists with phone numbers, travel apps, tourism research and live hotel data for AI agents. Trip.com is Ctrip's international site (携程国际版, 트립닷컴, トリップドットコム), a strong source for Chinese, Japanese, Korean and South-East Asian inventory. Whether you search for "trip.com scraper", "ctrip hotel scraper", "scrape trip.com hotel prices", "携程酒店数据采集", "携程酒店爬虫", "携程国际 酒店 价格 抓取" or "export trip.com hotels to excel", this is the tool.

### Table of contents

- [At a glance](#at-a-glance)
- [What you get: the Trip.com data fields](#what-you-get-the-tripcom-data-fields)
- [Who uses this Trip.com scraper](#who-uses-this-tripcom-scraper)
- [Cookbook: 12 ready-to-run inputs](#cookbook-12-ready-to-run-inputs)
- [Tutorial: scrape Trip.com in the Apify Console](#tutorial-scrape-tripcom-in-the-apify-console)
- [Tutorial: the Trip.com API from your own code](#tutorial-the-tripcom-api-from-your-own-code)
- [Input reference](#input-reference)
- [Output data dictionary with measured fill rates](#output-data-dictionary-with-measured-fill-rates)
- [Real output sample](#real-output-sample)
- [How it reads a whole city](#how-it-reads-a-whole-city)
- [How prices are reported](#how-prices-are-reported)
- [Scale and speed (measured)](#scale-and-speed-measured)
- [What you pay](#what-you-pay)
- [Integrations](#integrations)
- [Performance tips](#performance-tips)
- [Troubleshooting: every status message explained](#troubleshooting-every-status-message-explained)
- [Honest limits](#honest-limits)
- [Comparison: Trip.com's own tools, manual copying and this Actor](#comparison-tripcoms-own-tools-manual-copying-and-this-actor)
- [FAQ](#faq)
- [Glossary](#glossary)
- [Is it legal to scrape Trip.com?](#is-it-legal-to-scrape-tripcom)
- [Changelog](#changelog)
- [Support](#support)

### At a glance

| | |
|---|---|
| **Source** | www.trip.com hotel search (the international Trip.com site, 21 languages), hotel pages, room lists and guest reviews |
| **Input** | Destinations by name (city, area, landmark, metro station, hotel), list links or city IDs; hotel links or IDs; dates, rooms, guests; currency; language; order; filters |
| **Output** | One row per hotel (JSON, CSV, Excel, XML, RSS); optional `roomTypes` and `reviews` arrays inside the row |
| **Depth** | Each destination is read to the end of Trip.com's own list, with no page cap: 29,727 distinct hotels from 8 cities in one run (2026-10-29) |
| **Speed** | First rows within seconds after Chrome opens; about 88 hotels per second on the list; with hotel pages, rooms and reviews about 0.8 hotels per second |
| **Prices** | Per room per night before taxes, total for the stay with taxes and fees, taxes, original price, discount, in 40 currencies |
| **Pricing** | Pay per result (one result = one hotel row) with Store tier discounts; you set a maximum cost per run |

### What you get: the Trip.com data fields

Every row is one hotel for the dates, guests and currency of the run; the dictionary further down has every column with type and measured fill rate. In short:

- **Identity:** `hotelId` (stable ID, the key for joins), `url`, `name`, `nameEn`, `hotelCategory`; with hotel pages `localName`.
- **Ratings:** `starRating`, `ratingScore`, `ratingText`, `reviewsCount`, `ratingSubScores`; with hotel pages `recommendPercent`, exact `reviewsTotal`; with "Reviews per hotel" a `reviews` array (text, dates, sub-ratings, traveller type, country, hotel reply).
- **Prices:** `pricePerNight`, `totalPrice` (taxes and fees included), `taxesAndFees`, `originalPricePerNight`, `discountText`, `freeCancellation`, `breakfastIncluded`, `roomName`, `bedType`, `hasPrice`, `soldOut`.
- **Rooms and rates** (`includeRooms`, where Trip.com returns them): `roomTypes` with bed, size, facilities, photos and every rate with total, taxes, meal, exact cancellation deadline, payment option and rooms left.
- **Location:** `zone`, `cityName`, `latitude`/`longitude` (WGS-84), GCJ-02 and BD-09 grids for China; with hotel pages `address`, `phone`, `email`, `transitInfo`, `nearbyPlaces`.
- **Profile** (`includeDetails`): opening year, rooms, description, check-in/out times, policies, amenities by category.
- **Media, tags, context:** `imageUrl`, `images`, `videoUrl`, `highlights`, `awardTitle`, `isAd`, `checkIn`, `checkOut`, `rank`, `scrapedAt`.

### Who uses this Trip.com scraper

1. **Revenue managers and hoteliers** track their own hotel and comp set every morning: `hotelUrls` with ten IDs, `includeRooms: true`, a daily schedule.
2. **OTA and metasearch teams** compare Asian inventory and prices with Trip.com: a city per run, `sortBy: "lowest_price"`, joined on name and coordinates.
3. **Market analysts** size a destination: hotels, star classes, ratings, review volume and price bands of Bangkok in one run.
4. **Hotel-tech sales teams** build lead lists: `includeDetails: true` adds phone, email, address, opening year and room count.
5. **Travel-planning apps** pull live offers for a city and dates, filter by guest rating and price, and link to the Trip.com page.
6. **Researchers** study tourism supply, pricing and review sentiment; the stable `hotelId` supports panels over weeks.
7. **Corporate travel managers** compare negotiated rates with Trip.com's public rates.
8. **Investors and developers** screen a district: openings, room counts, ratings and prices.
9. **Reputation teams** download the latest 50–200 reviews with sub-ratings, traveller type and the hotel's reply.
10. **Content teams** compile "best hotels near Shibuya Station" lists with current prices and photos.
11. **AI-agent builders** give an assistant a tool that answers "4-star hotels in Tokyo under $150 with free cancellation next weekend" with real rows.
12. **Price-intelligence platforms and tourism boards** watch campaigns ("China travel deal"), tax-and-fee structures and property counts over time.

### Cookbook: 12 ready-to-run inputs

Paste any of these into the JSON input tab. Dates default to seven days ahead, one night, two adults, one room.

#### 1. The 500 best-reviewed hotels of a city

```json
{ "destinations": ["Bangkok"], "sortBy": "top_reviewed", "maxItems": 500 }
```

#### 2. The whole list of a city, bookable hotels only, with the gap-filling second pass

```json
{ "destinations": ["Tokyo"], "maxItems": 0, "fillGaps": true, "onlyAvailable": true }
```

`maxItems: 0` means no limit; `onlyAvailable` skips sold-out hotels (not saved, not charged); `fillGaps` adds what a second pass finds (see "How it reads a whole city").

#### 3. Hotels around a metro station, landmark or area

```json
{ "destinations": ["Shibuya Station", "Marina Bay Sands", "Sukhumvit"], "maxItems": 300 }
```

Each name goes through Trip.com's own destination search.

#### 4. Family stay: three adults, two children, two rooms

```json
{ "destinations": ["Shanghai"], "checkInDate": "+30", "nights": 2, "rooms": 2, "adults": 3, "children": 2, "childrenAges": ["5", "11"], "maxItems": 500 }
```

#### 5. Luxury shortlist with every room rate

```json
{ "destinations": ["Dubai"], "starRatings": ["5"], "minGuestRating": "9", "freeCancellation": true, "includeRooms": true, "maxItems": 100 }
```

#### 6. Budget band with breakfast

```json
{ "destinations": ["Kuala Lumpur"], "minPrice": 30, "maxPrice": 80, "breakfastIncluded": true, "currency": "USD", "maxItems": 1000 }
```

#### 7. Track specific hotels every day

```json
{ "hotelUrls": ["993510", "https://www.trip.com/hotels/detail/?hotelId=759807"], "checkInDate": "+7", "nights": 1, "includeRooms": true }
```

Schedule it daily; `hotelId` plus `checkIn` make a clean time series.

#### 8. Lead list with phone numbers and addresses

```json
{ "destinations": ["Ho Chi Minh City"], "includeDetails": true, "sortBy": "star_rating", "maxItems": 2000 }
```

#### 9. Latest reviews of a hotel set

```json
{ "hotelUrls": ["72926277", "38322346"], "maxReviewsPerHotel": 100, "reviewsSort": "most_recent" }
```

#### 10. Japanese hotel names and yen prices

```json
{ "destinations": ["Osaka"], "language": "ja-JP", "currency": "JPY", "maxItems": 500 }
```

#### 11. Many cities in one run, 300 hotels each

```json
{ "destinations": ["Seoul", "Busan", "Taipei", "Hong Kong", "Macau"], "maxItemsPerDestination": 300, "maxItems": 0 }
```

#### 12. A Trip.com list link as the destination, full profile of the top 50

```json
{ "destinations": ["https://www.trip.com/hotels/list?city=228&checkin=2026/11/10&checkout=2026/11/11"], "includeDetails": true, "includeRooms": true, "maxReviewsPerHotel": 20, "maxItems": 50 }
```

The city ID in the link is used; dates and guests come from the input fields.

### Tutorial: scrape Trip.com in the Apify Console

1. Open the Actor and press **Try for free**. The form opens with a small prefill: Shanghai, 20 hotels.
2. Type one or more **destinations**: a city ("Tokyo"), an area ("Shibuya"), a landmark ("Marina Bay Sands"), a metro station ("Shinjuku Station") or a hotel name. Paste a Trip.com list link instead if you have one.
3. Set **check-in** and **check-out** (`2026-12-20`, or `+14` for fourteen days from today), rooms, adults and children, and the **currency** and **language** of prices and names.
4. Pick the **order**: top reviewed (default), lowest or highest price, star rating, distance. Add filters if you only need a slice.
5. Set **Max hotels** (0 = no limit). Leave the three switches (hotel pages, room rates, reviews) off for the fastest run; turn them on when you need phone numbers, policies, rates or review text.
6. Press **Start**. Rows appear a few seconds after the browser has opened; the status line shows progress ("Saved 1,250/5,000 hotels · now: Tokyo, Japan").
7. Open the **Output** tab (views: Overview, Prices & deals, Location & contact) and export as JSON, CSV, Excel, XML or RSS.

### Tutorial: the Trip.com API from your own code

Replace `YOUR_TOKEN` with your Apify API token (Settings, Integrations). The Actor ID is `logiover/trip-com-scraper`.

**curl** (one call, good for up to a few hundred hotels; for big runs start the run, then read `/datasets/<id>/items?format=csv`):

```bash
curl -s -X POST "https://api.apify.com/v2/acts/logiover~trip-com-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"destinations": ["Tokyo"], "checkInDate": "+14", "maxItems": 100}'
```

**Node.js** (`npm i apify-client`):

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('logiover/trip-com-scraper').call({
    destinations: ['Seoul'], checkInDate: '+14', nights: 2, currency: 'KRW', maxItems: 1000,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0].name, items[0].pricePerNight, items[0].priceCurrency);
```

**Python** (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("logiover/trip-com-scraper").call(run_input={
    "destinations": ["Singapore"], "checkInDate": "+14", "includeDetails": True, "maxItems": 200,
})
for hotel in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(hotel["hotelId"], hotel["name"], hotel["pricePerNight"], hotel.get("phone"))
```

Every run also writes a `SUMMARY` record to the default key-value store: outcome, rows saved, requests, per-destination counts and stop reasons, the route used and the browser statistics. Read it at `https://api.apify.com/v2/key-value-stores/<defaultKeyValueStoreId>/records/SUMMARY`.

### Input reference

All inputs are optional except that a run needs at least one destination or hotel link. This table is generated from the Actor's input schema, so it matches the form exactly.

| Input | Type | Default | What it does |
|---|---|---|---|
| `destinations` | list | empty | **Destinations.** City, area, landmark, metro station or hotel name; a Trip.com list link; or `cityId:228`. |
| `checkInDate` | text | – | **Check-in date.** `YYYY-MM-DD` or `+N` for N days from today. Default: today + 7. |
| `checkOutDate` | text | – | **Check-out date.** `YYYY-MM-DD` or `+N`. Empty = check-in + Nights. |
| `nights` | number | `1` | **Nights.** Length of stay when no check-out date is given (1–30). |
| `rooms` | number | `1` | **Rooms.** Number of rooms (1–8). |
| `adults` | number | `2` | **Adults.** Number of adult guests in total (1–10). |
| `children` | number | `0` | **Children.** Number of children (0–6). |
| `childrenAges` | list | empty | **Children's ages.** One age per child, 0–17 (e.g. 4 and 9). |
| `currency` | choice | `"USD"` | **Currency.** Currency of every price in the output; Trip.com converts at its own rate. 40 currencies. |
| `language` | choice | `"en-XX"` | **Language.** Language of hotel names, areas, rating words, policies and amenities. 21 locales. |
| `sortBy` | choice | `"top_reviewed"` | **Order.** Which hotels come first (the "rank" column). Values: `top_reviewed`, `lowest_price`, `highest_price`, `star_rating`, `distance`, `recommended`. |
| `maxItems` | number | `1000` | **Max hotels.** Stop after this many unique hotels across all destinations and links. |
| `maxItemsPerDestination` | number | `0` | **Max hotels per destination.** Optional cap per destination, so one big city does not take the whole "Max hotels". |
| `fillGaps` | yes/no | `false` | **Second pass to catch missed hotels.** After a destination's list ended, read it again in another order and add the hotels the first pass missed (about doubles the time). |
| `onlyAvailable` | yes/no | `false` | **Skip sold-out hotels.** Save only hotels that have a nightly price; skipped hotels are not saved and not charged. |
| `starRatings` | list | empty | **Star rating.** Only hotels of these star classes (Trip.com's own star or diamond rating). Values: `5`, `4`, `3`, `2`. |
| `minGuestRating` | choice | empty | **Minimum guest rating.** Only hotels rated at least this on Trip.com's 10-point guest score. Values: `6`, `7`, `8`, `9`. |
| `minPrice` | number | `0` | **Minimum price per night.** Only hotels from this nightly price (per room, before taxes and fees), in the chosen currency. |
| `maxPrice` | number | `0` | **Maximum price per night.** Only hotels up to this nightly price (per room, before taxes and fees), in the chosen currency. |
| `freeCancellation` | yes/no | `false` | **Free cancellation only.** Only hotels with at least one free-cancellation rate for your dates. |
| `breakfastIncluded` | yes/no | `false` | **Breakfast included only.** Only hotels with a rate that includes breakfast. |
| `bedTypes` | list | empty | **Bed type.** Only hotels with rooms of these bed types. Values: `double`, `king`, `single`, `two_beds`, `three_beds`, `four_plus`. |
| `paymentType` | choice | empty | **Payment.** Only hotels offering this payment option. Values: `pay_at_hotel`, `prepay_online`, `no_credit_card`. |
| `includeDetails` | yes/no | `false` | **Hotel pages.** Open each hotel's page: local name, phone, email, full address, transit, policies, amenities. |
| `includeRooms` | yes/no | `false` | **Room types and rates.** Add every room type with every rate for your dates. |
| `maxReviewsPerHotel` | number | `0` | **Reviews per hotel.** Add up to this many guest reviews per hotel (0–200). |
| `reviewsSort` | choice | `"most_recent"` | **Reviews order.** Which reviews come first when "Reviews per hotel" is set. Values: `most_recent`, `most_relevant`, `rating_high_to_low`, `rating_low_to_high`. |
| `hotelUrls` | list | empty | **Hotel links or IDs.** Specific hotels: Trip.com hotel links or bare hotel IDs. |
| `proxyConfiguration` | object | `{"useApifyProxy": true}` | **Proxy configuration.** Used only as a fallback. |

A check-in in the past is moved to seven days ahead; stays are limited to 30 nights. `destinations` accepts plain names, a Trip.com list link (`https://www.trip.com/hotels/list?city=2&...`, the `city` value is used) and `cityId:228` (Tokyo).

### Output data dictionary with measured fill rates

Fill rates: 29,727 rows of the 2026-10-29 run (8 cities, default settings) for list columns; 150 rows of a 4-city (Tokyo, Bangkok, Shanghai, Seoul) run with hotel pages, rooms and 20 reviews each for the columns marked pages, rooms or reviews.

| Column | Type | Fill | Meaning, example |
|---|---|---|---|
| `hotelId` | text | 100 % | Trip.com hotel ID; stable across runs, the key for joins |
| `url` | text | 100 % | Hotel page on Trip.com for the run's dates and guests; e.g. `https://www.trip.com/…` |
| `name` | text | 100 % | Hotel name in the run's language |
| `nameEn` | text | 100 % | English hotel name |
| `hotelCategory` | text | 99.4 % | Property type (Hotel, Hostel, Apartment…); when Trip.com names a category; e.g. `Hotel` |
| `localName` | text | 100 % pages | Name in the local script, from the hotel page; e.g. `グランドニッコー東京 台場` |
| `nameLocale` | text | 100 % pages | Language tag of that local name |
| `starRating` | number | 94.1 % | Star class 1–5 (Trip.com's own grade if unrated); ungraded properties have none; e.g. `4` |
| `ratingScore` | number | 95.2 % | Guest score on a 0–10 scale; only reviewed hotels; e.g. `9.8` |
| `ratingText` | text | 68.0 % | Trip.com's word for the score (Outstanding…); only reviewed hotels; e.g. `Perfect` |
| `reviewsCount` | number | 94.2 % | Reviews on the list card; huge counts come rounded (13.6K = 13600); only reviewed hotels; e.g. `25738` |
| `ratingSubScores` | object | 95.2 % | Cleanliness, Amenities, Location, Service scores; only reviewed hotels; e.g. `{"Cleanliness"…` |
| `reviewHighlights` | text | 66.1 % | Guest comment tags, joined with ' | '; only reviewed hotels; e.g. `Offers pick-up…` |
| `reviewSnippet` | text | 77.2 % | One guest sentence shown on the card; only reviewed hotels; e.g. `The hotel prov…` |
| `starRatingType` | text | 100 % pages | Official star or Trip.com's own diamond grade; e.g. `star` |
| `recommendPercent` | number | 100 % pages | Share of guests who recommend the hotel, in percent; e.g. `94` |
| `reviewsTotal` | number | 100 % pages | Exact review count from the hotel page; e.g. `1826` |
| `ratingSubScoresDetail` | object | 100 % pages | Sub-scores from the hotel page (object); e.g. `{"Cleanliness"…` |
| `reviewQualities` | text | 100 % pages | Qualities guests mention, joined with ' | '; e.g. `Large rooms \| …` |
| `reviews` | array | 100 % reviews | Array of guest reviews (fields below); e.g. `[{"reviewId":"…` |
| `reviewsFetched` | number | 100 % reviews | How many reviews this row carries |
| `pricePerNight` | number | 75.8 % | Cheapest card offer, per room and night, before taxes; empty without a price; e.g. `49` |
| `priceCurrency` | text | 100 % | ISO currency code of every amount in the row; e.g. `USD` |
| `priceDisplay` | text | 75.8 % | The price as Trip.com prints it; empty without a price; e.g. `US$49` |
| `totalPrice` | number | 75.8 % | Whole stay (all nights and rooms) with taxes and fees; empty without a price; e.g. `52.44` |
| `totalPriceDisplay` | text | 75.8 % | The total as Trip.com prints it; empty without a price; e.g. `US$52.44` |
| `taxesAndFees` | number | 75.7 % | Tax and fee part of the total; empty without a price; e.g. `2.95` |
| `stayPriceBeforeDiscount` | number | 75.8 % | Room price for the stay before discount and before taxes; empty without a price; e.g. `74.2` |
| `discountAmount` | number | 38.2 % | Discount for the stay as a positive amount; only when a discount applies; e.g. `24.71` |
| `originalPricePerNight` | number | 37.1 % | Struck-through price per night; only when a struck-through price is shown; e.g. `74` |
| `discountText` | text | 37.1 % | Discount label, e.g. 35% off; only when a discount applies; e.g. `32% off` |
| `promotionText` | text | 45.2 % | Campaign labels, joined with ' | '; only when a campaign applies; e.g. `Special Discou…` |
| `paymentText` | text | 100 % | Payment option of the offer: Prepay Online or Pay at Hotel; e.g. `Prepay Online` |
| `freeCancellation` | bool | 75.8 % | True when the cheapest offer has free cancellation; empty without a price; empty without a price |
| `breakfastIncluded` | bool | 75.8 % | True when the cheapest offer includes breakfast; empty without a price; empty without a price |
| `roomName` | text | 75.8 % | Room type of the cheapest offer; empty without a price |
| `bedType` | text | 74.5 % | Beds of that room; empty without a price |
| `roomTags` | text | 78.3 % | All tags of the offer, joined with ' | '; empty without a price; e.g. `Free Cancellat…` |
| `lastBookedText` | text | 56.0 % | Urgency note (Last booked 7 mins ago); only when Trip.com shows it; e.g. `Last booked 3 …` |
| `hasPrice` | bool | 100 % | True when the card has a nightly price; false = sold out or no offer |
| `soldOut` | bool | 100 % | True when the card says the hotel is sold out for your dates (no price, tagged Sold out) |
| `zone` | text | 100 % | Trip.com's area of the hotel |
| `positionDescription` | text | 100 % | Nearby anchors, joined with ' | ' |
| `cityId` | number | 100 % | Trip.com city ID |
| `cityName` | text | 100 % | City name in the run's language |
| `cityNameEn` | text | 100 % | City name in English |
| `provinceId` | number | 100 % | Trip.com province or region ID |
| `countryId` | number | 100 % | Trip.com country ID |
| `isOverseas` | bool | 100 % | True outside mainland China, from Trip.com's point of view |
| `latitude`, `longitude` | number | 100 % | Position in WGS-84 (GPS, Google Maps); e.g. `40.06121882066…` |
| `latitudeGcj02`, `longitudeGcj02` | number | 50.6 % | Position on the Chinese GCJ-02 grid; mainland China only; e.g. `40.062271` |
| `latitudeBd09`, `longitudeBd09` | number | 100 % | Position on Baidu's BD-09 grid; e.g. `40.067934` |
| `phone` | text | 100 % pages | Hotel phone as shown on the page; e.g. `+81-3-55006711` |
| `email` | text | 89.3 % pages | Hotel email as shown on the page; e.g. `reservations@t…` |
| `countryName` | text | 100 % pages | Country name |
| `provinceName` | text | 26.0 % pages | Province or state name |
| `address` | text | 100 % pages | Full street address from the hotel page |
| `zoneName` | text | 92.0 % pages | Area name from the hotel page |
| `transitInfo` | text | 100 % pages | Nearest metro or station and walking time |
| `nearbyPlaces` | array | 100 % pages | Array: name, type, distance, metres; e.g. `[{"name":"Daib…` |
| `openedYear` | number | 99.3 % pages | Year the hotel opened; e.g. `1996` |
| `numberOfRooms` | number | 100 % pages | Number of rooms; e.g. `882` |
| `description` | text | 98.7 % pages | Hotel description, plain text; e.g. `Located along …` |
| `checkInFrom` | text | 100 % pages | Check-in time window; e.g. `After 15:00` |
| `checkOutUntil` | text | 100 % pages | Check-out time; e.g. `Before 11:00` |
| `frontDeskHours` | text | 99.3 % pages | Front-desk opening hours; e.g. `24/7` |
| `childPolicy` | text | 100 % pages | Rules for children; e.g. `Children of al…` |
| `extraBedPolicy` | text | 100 % pages | Cribs and extra beds; e.g. `For all room t…` |
| `breakfastPolicy` | text | 99.3 % pages | Breakfast rules and price; e.g. `This property …` |
| `depositPolicy` | text | 80.7 % pages | Deposit rules; e.g. `Deposit: No de…` |
| `petPolicy` | text | 100 % pages | Pet rules; e.g. `Pets are not a…` |
| `ageRequirement` | text | 100 % pages | Minimum check-in age; e.g. `There is no ag…` |
| `guestsAccepted` | text | 16.7 % pages | Guest restrictions, e.g. local guests only; e.g. `Guests from al…` |
| `paymentAtHotel` | text | 56.7 % pages | Accepted payment methods at the hotel; e.g. `Cash` |
| `amenities` | array | 100 % pages | Flat array of all amenities; e.g. `["Wi-Fi in pub…` |
| `amenitiesByCategory` | object | 100 % pages | Category (Internet, Parking…) to amenity list; e.g. `{"Internet":["…` |
| `popularAmenities` | array | 100 % pages | Amenities Trip.com highlights; e.g. `["Private park…` |
| `amenitiesCount` | number | 100 % pages | Number of amenities |
| `detailHighlights` | text | 100 % pages | Page highlights, joined with ' | '; e.g. `Bay views \| Ga…` |
| `awardUrl` | text | 34.7 % pages | Link to Trip.com's ranking list the hotel appears in; e.g. `https://www.trip.com/…` |
| `roomTypes` | array | 14.7 % rooms | Array of room types with their rates (keys below); only when Trip.com returned rooms; e.g. `[{"roomTypeId"…` |
| `roomTypesCount` | number | 14.7 % rooms | Number of room types; only when Trip.com returned rooms |
| `ratesCount` | number | 14.7 % rooms | Number of rates across all room types; only when Trip.com returned rooms |
| `cheapestRatePerNight` | number | 14.7 % rooms | Lowest rate per night in the room list; only when Trip.com returned rooms; e.g. `152` |
| `cheapestRateTotal` | number | 14.7 % rooms | Total of that rate with taxes and fees; only when Trip.com returned rooms; e.g. `166.9` |
| `cheapestRateRoom` | text | 14.7 % rooms | Room type of that rate; only when Trip.com returned rooms |
| `roomsSoldOut` | bool | 14.7 % rooms | True when no room matches your party exactly (rates shown are alternatives); only when Trip.com returned rooms |
| `imageUrl` | text | 99.4 % | Main photo; e.g. `https://ak-d.tripcdn.com/…` |
| `images` | array | 99.4 % | List-card photos (array of URLs); e.g. `["https://ak-d…` |
| `videoUrl` | text | 21.3 % | Hotel video; only hotels with a video; e.g. `https://video.c-ctrip.com/…` |
| `highlights` | text | 96.9 % | Highlight tags, joined with ' | '; e.g. `free airport s…` |
| `hotelTags` | text | 32.9 % | Trip.com labels such as Hi China!, joined with ' | '; only tagged hotels; e.g. `Hi China!` |
| `awardTitle` | text | 2.1 % | Ranking title, e.g. No. 3 of 4-Star Select Hotels; only ranked hotels; e.g. `No. 8 of 4-Sta…` |
| `awardRank` | number | 2.1 % | Position in that ranking; only ranked hotels |
| `isAd` | bool | 100 % | True for a sponsored placement (recommended order only) |
| `photos` | array | 100 % pages | Hotel page photos (array, up to 30); e.g. `["https://ak-d…` |
| `photosTotal` | number | 100 % pages | Photos Trip.com holds for the hotel |
| `checkIn`, `checkOut`, `nights`, `adults`, `children` | text / number | 100 % | The search of the run: dates (ISO), nights and guests |
| `rooms` | number | 100 % | Rooms in the search (number); e.g. `1` |
| `searchDestination` | text | 100 % | The destination text that found the hotel |
| `sortBy` | text | 100 % | Order of the pass that found the hotel |
| `rank` | number | 100 % | Position in that order (first pass only) |
| `detailsStatus` | text | 100 % | State of the optional parts: details ok, rooms ok, reviews N; e.g. `not requested` |
| `scrapedAt` | text | 100 % | Time the run started, ISO; e.g. `2026-10-29T09:…` |

Keys inside the arrays, measured in the details+rooms+reviews run:

- **`roomTypes[]`** (room types, 219 measured). Always filled: `roomTypeId`, `roomType`, `bed`, `smoking`, `maxGuests`, `facilities`, `photos`, `ratesCount`, `cheapestPricePerNight`, `rates`. Sometimes empty: `area` 99.5 %, `floor` 63.9 %, `window` 99.5 %, `wifi` 99.1 %.
- **`roomTypes[].rates[]`** (rates, 1,631 measured). Always filled: `rateId`, `roomCode`, `meal`, `cancellation`, `freeCancellation`, `payment`, `instantConfirmation`, `pricePerNight`, `currency`, `priceDisplay`, `totalPrice`, `totalPriceDisplay`, `taxesAndFees`, `maxGuests`, `bookable`. Sometimes empty: `originalPricePerNight` 0 %, `totalDiscount` 0 %, `propertyCurrencyPrice` 38.0 %, `remainingRooms` 99.8 %, `labels` 69.5 %.
- **`reviews[]`** (guest reviews, 3,000 measured). Always filled: `reviewId`, `createdAt`, `stayDate`, `rating`, `ratingLocation`, `ratingAmenities`, `ratingService`, `ratingCleanliness`, `recommend`, `content`, `language`, `travelType`, `userName`, `userReviews`, `usefulCount`. Sometimes empty: `ratingText` 96.3 %, `roomType` 99.7 %, `userCountry` 86.3 %, `userCountryCode` 88.8 %, `images` 97.5 %, `hotelReply` 75.3 %, `hotelReplyDate` 75.3 %.
- **`nearbyPlaces[]`** (nearby places, 1,482 measured). Always filled: `name`, `type`, `distance`, `distanceMeters`.

### Real output sample

Two rows from the platform runs of 2026-10-29, unmasked, long lists shortened with "…", some keys left out for length.

**List row** (default settings):

```json
{
 "hotelId": "608516",
 "url": "https://www.trip.com/hotels/detail/?hotelId=608516&checkin=2026…",
 "name": "CitiGO Hotel Sanyuanqiao Beijing",
 "nameEn": "CitiGO Hotel Sanyuanqiao Beijing",
 "hotelCategory": "Hotel",
 "starRating": 4,
 "ratingScore": 9.6,
 "ratingText": "Excellent",
 "reviewsCount": 14743,
 "ratingSubScores": {
  "Cleanliness": 9.7,
  "Amenities": 9.5,
  "Location": 9.6,
  "Service": 9.7
 },
 "reviewHighlights": "Easy to get around | Convenient location",
 "reviewSnippet": "The decor is modern and distinctive, and the room is very quiet.",
 "pricePerNight": 72,
 "priceCurrency": "USD",
 "totalPrice": 75.68,
 "taxesAndFees": 4.16,
 "stayPriceBeforeDiscount": 79.7,
 "discountAmount": 8.18,
 "originalPricePerNight": 80,
 "discountText": "10% off",
 "promotionText": "China travel deal",
 "paymentText": "Prepay Online",
 "freeCancellation": true,
 "breakfastIncluded": false,
 "roomName": "King Room",
 "bedType": "1 queen bed",
 "lastBookedText": "Last booked 21 mins ago",
 "hasPrice": true,
 "soldOut": false,
 "zone": "China International Exhibition Center Area",
 "positionDescription": "Near Coal Industry Exhibition Center | National Stadium-Bird's …",
 "cityId": 1,
 "cityName": "Beijing",
 "countryId": 1,
 "isOverseas": false,
 "latitude": 39.95989778949662,
 "longitude": 116.44867953255331,
 "latitudeGcj02": 39.961257,
 "longitudeGcj02": 116.454867,
 "imageUrl": "https://ak-d.tripcdn.com/images/1mc3y12000c2ukniw8AAB_R_600_600…",
 "images": [
  "https://ak-d.tripcdn.com/images/1mc3y12000c2ukniw8AAB_R_600_600…",
  "https://ak-d.tripcdn.com/images/0203u120008xrnxh1DC5C_R_600_600…"
 ],
 "videoUrl": "https://video.c-ctrip.com/videos/u00qcn1538kh4jcgg15CD.mp4",
 "highlights": "Free luggage storage | Design hotel | Artistic ambiance | Excel…",
 "hotelTags": "Hi China!",
 "awardTitle": "No. 8 of 4-Star Select Hotels in Beijing",
 "awardRank": 8,
 "isAd": false,
 "checkIn": "2026-11-05",
 "checkOut": "2026-11-06",
 "rooms": 1,
 "searchDestination": "Beijing",
 "sortBy": "top_reviewed",
 "rank": 11,
 "detailsStatus": "not requested",
 "scrapedAt": "2026-10-29T09:18:42.590Z"
}
```

**Row with hotel page, rooms and reviews** (`includeDetails`, `includeRooms`, `maxReviewsPerHotel`):

```json
{
 "hotelId": "104599557",
 "name": "HOTEL GROOVE SHINJUKU, A PARKROYAL Hotel",
 "pricePerNight": 294,
 "priceCurrency": "USD",
 "starRatingType": "star",
 "openedYear": 2023,
 "numberOfRooms": 538,
 "phone": "+81-3-62659220",
 "nearbyPlaces": [
  {
   "name": "Shinjuku Station",
   "type": "Train station",
   "distanceMeters": 520
  },
  "…"
 ],
 "amenitiesByCategory": {
  "Internet": [
   "Wi-Fi in public areas (Free)"
  ],
  "Parking": [
   "Parking"
  ]
 },
 "recommendPercent": 91,
 "reviewsTotal": 1547,
 "roomTypes": [
  {
   "roomTypeId": "397587482",
   "roomType": "Superior Twin",
   "bed": "2 single beds",
   "area": "22㎡",
   "maxGuests": 2,
   "facilities": [
    "City view",
    "Private bathroom",
    "…"
   ],
   "photos": [
    "https://ak-d.tripcdn.com/images/0226t12000r…"
   ],
   "ratesCount": 2,
   "cheapestPricePerNight": 361,
   "rates": [
    {
     "rateId": "1355233411",
     "meal": "Great breakfast for US$27.57 (optional)",
     "cancellation": "Free cancellation before 15:00, Nov 4, 2026…",
     "freeCancellation": true,
     "payment": "Pay at hotel",
     "instantConfirmation": true,
     "pricePerNight": 361,
     "currency": "USD",
     "totalPrice": 448.77,
     "taxesAndFees": 87.73,
     "propertyCurrencyPrice": "Property currency: JPY 70,851",
     "maxGuests": 2,
     "remainingRooms": 8,
     "bookable": true,
     "labels": "Free Cancellation before 15:00, Nov 4"
    }
   ]
  }
 ],
 "ratesCount": 47,
 "cheapestRatePerNight": 361,
 "cheapestRateTotal": 448.77,
 "roomsSoldOut": false,
 "reviews": [
  {
   "reviewId": "2079372057",
   "createdAt": "2026-08-25T18:38:05",
   "stayDate": "2026-08-01",
   "rating": 10,
   "ratingLocation": 10,
   "ratingAmenities": 10,
   "ratingService": 10,
   "ratingCleanliness": 10,
   "ratingText": "Outstanding",
   "recommend": true,
   "content": "非常不錯哦！除了聲音有點吵，服務特別好！有中文服務，進店還送了飲料，我們住了5天，因為…",
   "language": "zh",
   "travelType": "Family",
   "roomType": "Deluxe Triple",
   "userName": "daydreamLu",
   "userCountry": "China",
   "userCountryCode": "CN",
   "userReviews": 9,
   "usefulCount": 0,
   "images": [
    "https://ak-d.tripcdn.com/images/0234712000t…",
    "https://ak-d.tripcdn.com/images/0230w12000t…",
    "…"
   ],
   "hotelReply": "Dear Valued Guest,Thank you very much for s…",
   "hotelReplyDate": "2026-08-29"
  }
 ]
}
```

**CSV columns of the list row:** hotelId, url, name, nameEn, hotelCategory, starRating, ratingScore, ratingText, reviewsCount, ratingSubScores, reviewHighlights, reviewSnippet, pricePerNight, priceCurrency, priceDisplay, totalPrice, totalPriceDisplay, taxesAndFees, stayPriceBeforeDiscount, discountAmount, originalPricePerNight, discountText, promotionText, paymentText, freeCancellation, breakfastIncluded, roomName, bedType, roomTags, lastBookedText, hasPrice, soldOut, zone, positionDescription, cityId, cityName, cityNameEn, provinceId, countryId, isOverseas, latitude, longitude, latitudeGcj02, longitudeGcj02, latitudeBd09, longitudeBd09, imageUrl, images, videoUrl, highlights, hotelTags, awardTitle, awardRank, isAd, checkIn, checkOut, nights, adults, children, rooms, searchDestination, sortBy, rank, detailsStatus, scrapedAt.

**What the big run looked like, city by city** (USD, one night on 2026-11-05, two adults; medians over hotels with a price):

| City | Hotels | With a price | Median per night | Median rating | Free cancellation | Breakfast included |
|---|---|---|---|---|---|---|
| Shanghai | 8,898 | 81 % | $38 | 9.1 | 96 % | 10 % |
| Beijing | 6,156 | 74 % | $53 | 9.3 | 98 % | 10 % |
| Tokyo | 2,272 | 98 % | $132 | 8.8 | 59 % | 6 % |
| Bangkok | 3,348 | 88 % | $34 | 8.7 | 53 % | 8 % |
| Dubai | 2,324 | 47 % | $129 | 8.9 | 47 % | 6 % |
| Istanbul | 2,929 | 82 % | $71 | 8.4 | 26 % | 40 % |
| Seoul | 3,231 | 51 % | $77 | 8.8 | 71 % | 7 % |
| Singapore | 569 | 79 % | $95 | 8.5 | 31 % | 7 % |

In CSV and Excel exports, arrays and objects (`images`, `roomTypes`, `reviews`, `amenitiesByCategory`) are written as JSON text in one cell; use the JSON export when you want them as structures.

### How it reads a whole city

Trip.com's search hands out hotels 25 per page, in the order you chose, and prints an announced counter ("6,951 properties" for Tokyo). The Actor asks for page 1, remembers the counter, then requests pages in a sliding window of eight until Trip.com's own end-of-list marker arrives. Every hotel is de-duplicated by `hotelId` before it is saved or charged. Measured on 2026-10-29 (one night, two adults, one room, top-reviewed order, default settings, 29,727 distinct hotels, 0 duplicates):

| Destination | Trip.com announced | Hotels delivered | Share | Pages read | Repeats skipped |
|---|---|---|---|---|---|
| Shanghai | 9,382 | 8,898 | 95 % | 376 | 483 |
| Beijing | 6,249 | 6,156 | 99 % | 250 | 88 |
| Tokyo | 6,951 | 2,272 | 33 % | 248 | 2,257 |
| Bangkok | 4,770 | 3,348 | 70 % | 163 | 427 |
| Dubai | 5,782 | 2,324 | 40 % | 120 | 415 |
| Istanbul | 2,980 | 2,929 | 98 % | 120 | 51 |
| Seoul | 3,435 | 3,231 | 94 % | 138 | 178 |
| Singapore | 583 | 569 | 98 % | 24 | 14 |

How to read these numbers:

- **The counter is not the market size.** The counter Trip.com prints is larger than the list it hands out. Tokyo announced 6,951 and delivered between 2,272 and 2,511 distinct hotels in four runs with different orders and passes, however many pages were read.
- **Deep pages repeat hotels.** The Tokyo run walked 248 pages (about 6,200 positions) and skipped 2,257 repeats, so more pages do not mean more hotels; the Actor still reads to the end marker, because new hotels trickle in until the last pages.
- **False last pages are re-asked.** Now and then Trip.com answers a page in the middle of a long list with 0 hotels, "last page" and a counter collapsed to about 190, sometimes again and again for the same page. The Actor re-asks such answers up to four times, then asks for the same positions in pages of 20. In the 29,727-hotel run it re-asked 182 times and recovered 3 pages through small pages (`falseEndsRetried`, `falseEndsRecovered` in `SUMMARY`). Without this, Dubai stopped at 217 of 5,787 announced hotels (build 1.0.4); the final run delivers 2,324 for the same search.
- **One pass can miss a few percent.** Hotels with equal scores or prices swap between pages while you page through. Tokyo, same dates, build 1.0.4: 2,273 hotels with the top-reviewed order, 2,458 with lowest price first, 2,530 in the union of the two. With `fillGaps: true` the Actor reads the list a second time in another order and adds only new hotels: 2,511 distinct hotels (99.2 % of the union), the second pass adding 203 to the 2,308 of the first, in 182 s instead of about 97 s.
- **The recommended order is for top-N pulls.** It mixes in sponsored cards and reshuffles between pages; read whole cities in the reviews, price, star or distance order.
- **Sold-out hotels are in the list.** 24 % of the rows of the big run have no price (highest: Dubai 53 %, Seoul 49 %, Beijing 26 %; see "With a price" in the city table under "Real output sample"), mostly at the end of the top-reviewed list. They carry `hasPrice: false`, `soldOut: true` when the card says "Sold out", and empty price columns. For price monitoring set `onlyAvailable: true`: sold-out hotels are skipped, neither saved nor charged (`soldOutSkipped` in `SUMMARY`).

For the most complete list of a destination use `fillGaps: true`, and read the result as "the hotels Trip.com lists for these dates", which is what a person scrolling the site sees.

### How prices are reported

- `pricePerNight` is the list-card price: per room, per night, before taxes and fees, for the cheapest offer; `roomName`, `bedType`, `freeCancellation`, `breakfastIncluded` and `paymentText` say what it buys.
- `totalPrice` is the whole stay (all nights, all rooms) including taxes and fees; `taxesAndFees` is the part that is tax. `originalPricePerNight`, `discountText`, `discountAmount` appear when Trip.com shows a struck-through price.
- Every amount is in the currency you chose (`priceCurrency`); Trip.com converts. In rooms mode `propertyCurrencyPrice` keeps the property's own currency where Trip.com shows it ("Property currency: JPY 13,500").
- **Alternatives.** When no room fits your party exactly, Trip.com lists "room types that aren't an exact match" (a capsule bed for one guest when you searched for two adults). `roomsSoldOut: true` in rooms mode marks that case, and a few list prices come from such alternatives.
- **No price.** Sold-out hotels have `hasPrice: false`; their price columns, `freeCancellation` and `breakfastIncluded` are empty.
- **Prices move by the minute.** A row is a snapshot at `scrapedAt`; for monitoring, schedule the run and join on `hotelId` and `checkIn`.

**Hand check, 2026-10-29.** 12 random hotels from the big run (Beijing, Shanghai, Tokyo, Bangkok, Istanbul) were compared with the hotel's own Trip.com page rendered in Chrome. Name, rating, rating text and review count were equal for 12 of 12. Nightly price and stay total matched the page (to the dollar the page shows), with the same free-cancellation flag, on the 6 pages that showed a price block; 1 hotel had no price in the list and none on its page; the other 5 pages showed no price block at all ("room types below aren't an exact match"), the alternatives case above.

### Scale and speed (measured)

All runs on the Apify platform on 2026-10-29, direct connection (no proxy traffic), 4,096 MB, one night, two adults, one room:

| Run | Hotels saved | Seconds | Hotels per second |
|---|---|---|---|
| Prefill: Shanghai, 20 hotels (the daily check) | 20 | 16 | – |
| 1,000 hotels, default settings | 1,000 | 30 | 33.4 |
| Tokyo, one pass, top-reviewed order (build 1.0.4) | 2,273 | 97 | 23.5 |
| Tokyo, one pass, lowest price first (build 1.0.4) | 2,458 | 143 | 17.2 |
| Tokyo, two passes with `fillGaps` (build 1.0.4) | 2,511 | 182 | 13.8 |
| 4 cities, hotel pages + rooms + 20 reviews each | 150 | 187 | 0.8 |
| 8 cities, whole lists, default settings | 29,727 | 339 | 87.6 |

- **Start-up** takes four to six seconds (Chrome opens, Trip.com's page loads once); the prefill run (Shanghai, 20 hotels) finished in 15.5 s end to end.
- **List mode** runs at roughly 88 hotels per second for large cities (up to six requests in flight per tab, two tabs).
- **Hotel pages, rooms and reviews** cost one page fetch, one room-list call and one call per ten reviews per hotel. Room calls are limited to three in flight, so the run with all three switched on and 20 reviews each did 0.8 hotels per second (150 hotels in 187 s).
- **Memory** peaked at 1,674 MB in the large run; the default of 4,096 MB leaves room for Chrome. Two destinations run at a time; `maxItems` is shared, `maxItemsPerDestination` limits each.

### What you pay

You pay per result: **one hotel row is one result**, however many rooms, rates or reviews the row carries. Store tiers apply automatically:

| Tier | 1,000 hotels | 10,000 hotels | 100,000 hotels |
|---|---|---|---|
| Free | $2.50 | $25.00 | $250.00 |
| Bronze | $2.20 | $22.00 | $220.00 |
| Silver | $1.90 | $19.00 | $190.00 |
| Gold, Platinum, Diamond | $1.60 | $16.00 | $160.00 |

Nothing is billed on top of the per-result price. **Maximum cost per run:** set it in the run options; the Actor reads it, saves only as many hotels as the limit pays for and ends the run as succeeded with a status message ("Saved N hotels — this run's maximum cost covers N results at the current price"). On the Free tier ($2.50 per 1,000) a limit of $0.05 pays for 20 hotels. Measured: the limit covered 22 results at the test account's tier price, and the run finished SUCCEEDED with exactly 22 hotels.

### Integrations

- **Webhooks and schedules.** Add a schedule and a webhook on "Run succeeded" in the Apify Console. With `"checkInDate": "+14"` every scheduled run prices the same horizon.
- **Make, Zapier, n8n.** Use the Apify module or node: "Run Actor" with the JSON input, then "Get dataset items".
- **Google Sheets, Excel, Airtable.** Export CSV from the Output tab or use the Apify add-on for Sheets; upsert on `hotelId` + `checkIn` and keep `scrapedAt` for price curves.
- **Warehouses.** Stream `/datasets/<id>/items?format=jsonl` into BigQuery, Snowflake, ClickHouse or S3; `roomTypes` and `reviews` map to repeated records.
- **MCP and AI agents.** Expose the Actor through Apify's MCP server; an agent calls it with destinations, dates and filters. Keep `maxItems` at 20–100 for interactive use.

### Performance tips

- Leave hotel pages, rooms and reviews off for market-wide pulls; run them with `hotelUrls` on the hotels you care about.
- Use `maxItems` for top-N questions and `fillGaps` only when completeness matters (it roughly doubles the reading time).
- Split huge jobs by city or use `maxItemsPerDestination`; keep the default 4,096 MB and proxy setting.
- For daily monitoring use `+N` dates, the same guests and `onlyAvailable: true`.

### Troubleshooting: every status message explained

Every run writes a `SUMMARY` record with an `outcome`: `COMPLETED`, `PARTIAL`, `EMPTY_RESULT` (succeed) or `BLOCKED`, `FETCH_FAILED`, `INVALID_INPUT`, `CRASHED` (fail with the message).

| Message (shortened) | Meaning and what to do |
|---|---|
| `COMPLETED: saved N hotels (max results reached) …` | You reached `maxItems`. Raise it, or use 0 |
| `COMPLETED: … (the end of Trip.com's list was reached) …` | Normal end: Trip.com's list had no more pages |
| `COMPLETED: … (stopped at the run time limit) …` | The run timeout came first. Raise it or split the job |
| `PARTIAL: saved N hotels … N request(s) could not be read` | Some pages were refused; the rest is saved. Run again |
| `Saved N hotels — this run's maximum cost … covers N results` (or `Saved 0 hotels …` when it covers none) | "Maximum cost per run" paid for N rows and the Actor stopped cleanly. Raise the limit |
| `No hotels matched — Trip.com answered but listed 0 hotels …` | `EMPTY_RESULT`: nothing for these filters and dates. Widen the filters or change dates |
| `Nothing to search. Add a destination …` | `INVALID_INPUT`: no destination and no hotel link |
| `Trip.com could not be opened: …` | `BLOCKED`: Chrome could not load Trip.com on any route. Retry later |
| `No hotels collected: Trip.com could not be read (…) after N request(s) …` | `BLOCKED` or `FETCH_FAILED`: every request was refused or failed; the brackets name the last error (e.g. `HTTP 431 anti-bot gray-listed this IP`). Retry later |
| `No hotels collected and N request(s) could not be read …` | `FETCH_FAILED`: an empty result cannot be confirmed |
| `Crashed after saving N hotels: …` | `CRASHED`: unexpected error; saved hotels are kept. Send us the run link |

Harmless warnings in the log and in `SUMMARY.notes`: a past check-in moved to seven days ahead; a check-out not after the check-in (nights used); stays over 30 nights shortened; minimum price above maximum (swapped); a language not served (replaced, e.g. `zh-CN` by `zh-HK`); `"…": Trip.com has no destination with this name` (check the spelling or paste a list link); `Not a Trip.com hotel link or hotel ID`; `Resumed after a platform restart: N hotel(s) were already saved and are not written or charged again`; `Trip.com keeps refusing the direct connection … switching to the residential proxy` (the route ladder at work).

Per-destination stop reasons in `SUMMARY.destinations[].stopReason`: `end of list`, `maxItems`, `maxItemsPerDestination`, `no new hotels` (40 pages in a row without a new hotel), `time limit`, `no hotels`, `no such destination`, `destination lookup failed`, `locale not served`, `search refused (…)`, `page N refused`, `error: …`. In each row `detailsStatus` tells what happened to the optional parts: `details ok`, `rooms ok`, `rooms none returned` (the room service answered without rooms), `rooms not loaded` (it refused the request), `reviews N`, or `… not loaded` / `… skipped (time limit)`.

### Honest limits

- **Only what Trip.com's list hands out for your dates and party.** The announced counter is larger than the list, and sold-out hotels are listed too (`hasPrice: false`; `onlyAvailable` skips them).
- **List prices can be alternatives.** The cheapest card price may belong to a room that is not an exact match for your party (`roomsSoldOut: true` in rooms mode).
- **Rooms mode is the least reliable part.** Trip.com's room service often refuses or empties room requests. Measured: a rooms-only run returned rooms for 27 of 30 Tokyo hotels, but for 0 of 12 Shanghai hotels (mainland China); with hotel pages and 20 reviews per hotel in the same run, 22 of 150 hotels in 4 cities got rooms (Tokyo 4 of 60, Bangkok 15 of 60, Shanghai 0 of 25, Seoul 3 of 5). Hotels without rooms say `rooms not loaded` or `rooms none returned` in `detailsStatus`, and their room columns are empty. Room calls are limited to three in flight, so such a run does about 0.8 hotels per second.
- **Snapshots.** Prices, rooms left and "last booked" notes change by the minute.
- **Dates and guests.** Check-in in the past moves to seven days ahead; stays are limited to 30 nights, parties to 8 rooms, 10 adults and 6 children.
- **Coordinates.** GCJ-02 only for mainland-China hotels (empty elsewhere).
- **Languages.** 21 locales; the mainland-China Chinese locale is mapped to Traditional Chinese; reviews stay in the language the guest wrote.
- **Review counts on cards.** Very large counts can be abbreviated by Trip.com ("13.6K"); the Actor converts to 13,600. `reviewsTotal` (hotel pages) is exact.
- **Not a booking tool.** No login, no booking, no member prices. After extreme use from one IP Trip.com can answer HTTP 431; the Actor then switches route.

### Comparison: Trip.com's own tools, manual copying and this Actor

| | Trip.com website by hand | Affiliate or partner feeds | This Actor |
|---|---|---|---|
| Access | Anyone, one page at a time | Application, approval, contract terms | One click or one API call |
| Volume | A few dozen hotels before it gets tedious | As agreed | Thousands of hotels per run |
| Dates and guests | One search at a time | Defined by the feed | Any dates, guests, currency, language per run |

The Actor reads what any visitor sees. It does not replace a partner agreement if you need booking rights or commissionable links.

### FAQ

#### How do I scrape Trip.com hotel prices?

Type a destination such as "Tokyo", set your dates and press Start. Each hotel arrives as one row with `pricePerNight`, `totalPrice`, `taxesAndFees` and the currency you chose.

#### Is there an official Trip.com hotel API?

Trip.com runs partner and affiliate programmes with their own terms. This Actor is the open alternative: it reads the public search results any visitor sees.

#### Does the Trip.com scraper need a login, cookies or an API key?

No. It reads public pages only. You need an Apify account to run it, nothing from Trip.com.

#### Can I scrape all hotels in a city?

You get the hotels Trip.com lists for your dates, read to the end of its list. Use `maxItems: 0` and, for the most complete result, `fillGaps: true`; `onlyAvailable: true` skips sold-out hotels. Trip.com's announced counter is larger than what its list delivers, so the result is not "every property in the city".

#### Why does Trip.com show more hotels than the scraper returns?

The counter on Trip.com is larger than the number of hotels its list hands out, and the list repeats hotels on deep pages. See "How it reads a whole city" for measured numbers.

#### How many hotels can I scrape in one run?

The longest run saved 29,727 distinct hotels from 8 cities in 339 seconds. There is no page cap; the limit is what Trip.com lists for your destinations.

#### How fast is it?

About 88 hotels per second in list mode on large cities, after four to six seconds of start-up. Hotel pages, rooms and reviews are slower: about 0.8 hotels per second with 20 reviews each.

#### Which currencies and languages are supported?

40 currencies (USD, EUR, GBP, CNY, HKD, JPY, KRW, SGD, THB and more) and 21 Trip.com locales, among them English, Traditional Chinese, Japanese, Korean, German, French, Spanish, Thai and Arabic. The mainland-China locale is not served by the international site and is mapped to Traditional Chinese.

#### Can I get the Chinese or Japanese hotel name?

Yes. Set `language` to `zh-HK`, `zh-TW` or `ja-JP`: `name` follows the language, `nameEn` stays English, and with `includeDetails` `localName` carries the name in the hotel's local script.

#### How do I scrape hotels near a metro station or landmark?

Type it as a destination ("Shibuya Station"); Trip.com's destination search resolves it and the Actor filters inside the city.

#### Can I get hotel phone numbers and emails?

Yes, with `includeDetails: true`: `phone`, `email` and the full `address` as the hotel page shows them; see the fill rates.

#### Can I scrape Trip.com reviews?

Yes: set `maxReviewsPerHotel` (up to 200) and `reviewsSort`. Each review has text, language, dates, four sub-ratings, traveller type, room, country and the hotel's reply.

#### How do I get room types and every rate?

Turn on `includeRooms`. Hotels get a `roomTypes` array of room types, and inside each one every rate with price, total, taxes, meal, cancellation deadline, payment option and rooms left. This is the least reliable mode: Trip.com's room service returned rooms for 27 of 30 Tokyo hotels in a rooms-only run, for none of the Shanghai hotels, and for 22 of 150 hotels when hotel pages and reviews were requested too. Room columns stay empty for the rest (`detailsStatus`: `rooms not loaded` or `rooms none returned`).

#### How do I monitor hotel prices every day?

Use `hotelUrls` or a city with relative dates (`"checkInDate": "+14"`), `onlyAvailable: true` and a daily Apify schedule. Join rows on `hotelId` and `checkIn`, and plot `pricePerNight` by `scrapedAt`.

#### What is the difference between pricePerNight and totalPrice?

`pricePerNight` is per room and night before taxes and fees. `totalPrice` is the whole stay, all nights and rooms, with taxes and fees; `taxesAndFees` is the tax part.

#### How do I get only free-cancellation hotels?

Set `freeCancellation: true`. Each row also has a `freeCancellation` flag for its cheapest offer, and rooms mode gives the exact deadline per rate.

#### How do I filter by star rating and guest rating?

`starRatings` takes 5, 4, 3 or 2 and `minGuestRating` takes 6, 7, 8 or 9. Trip.com applies both itself, so counts match the website.

#### How do I search for a family with children?

Set `adults`, `children`, `childrenAges` and `rooms`; Trip.com then prices rooms that fit the party.

#### Why is a price different from what I see on the website?

Prices change by the minute and depend on dates, guests, currency and market. Compare with the same inputs; `scrapedAt` tells when the row was read.

#### What do soldOut and roomsSoldOut mean?

`soldOut` (every row): the list card says the hotel is sold out for your dates; it has no price. `roomsSoldOut` (rooms mode): no room fits your party exactly, so the rates shown are Trip.com's "not an exact match" alternatives.

#### What does onlyAvailable do?

It skips hotels without a nightly price (sold out for your dates). Skipped hotels are not saved and not charged; use it for price monitoring.

#### Which coordinate system do latitude and longitude use?

WGS-84, the system of GPS and Google Maps. Mainland-China hotels also carry GCJ-02 values, and BD-09 values came with every hotel of the big run: the grids of Chinese map apps.

#### How do I export Trip.com hotels to Excel or CSV?

Choose Excel or CSV in the run's Output tab, or call `/datasets/<id>/items?format=xlsx`. Nested columns become JSON text in one cell.

#### Can I use the Trip.com scraper from Python or Node.js, and can I schedule it?

Yes to both: the API tutorial has `apify-client` examples for Python and Node.js, and Apify schedules start it hourly, daily or weekly.

#### What happens when Trip.com blocks the scraper?

The Actor starts on the direct connection and, if Trip.com refuses it, switches to a residential and then a datacenter proxy by itself; falsely empty pages are re-asked. If nothing works the run fails with a message instead of returning an empty dataset. No proxy setup is needed.

#### How much does it cost to scrape 10,000 hotels, and how do I cap a run?

$25.00 on the Free tier and $16.00 on Gold and above (see "What you pay"). Set "Maximum cost per run" to cap it; the Actor saves only what the limit pays for and finishes cleanly.

#### Is it legal to scrape Trip.com?

The Actor collects public information without logging in; see the legal section below.

#### Does it work for ctrip.com, the mainland-China site?

No. It reads www.trip.com, the international site. Hotels in mainland China appear there too, priced in your chosen currency.

#### How do I scrape a single hotel by URL or ID?

Put the link or ID into `hotelUrls`, optionally with `includeDetails`, `includeRooms` and `maxReviewsPerHotel`.

#### Why did my run end with fewer hotels than maxItems?

Trip.com's list ended first; the status message says "the end of Trip.com's list was reached". Try other dates, fewer filters, or `fillGaps`.

#### What does fillGaps do?

After the first pass reached the end of a destination's list, it reads the list a second time in another order and saves only the hotels the first pass missed.

### Glossary

| Term | Meaning |
|---|---|
| 携程 (Xiéchéng), Ctrip | The Chinese online travel company, today Trip.com Group Ltd. |
| 携程国际, Trip.com | The international site and app, www.trip.com |
| 酒店 (jiǔdiàn) | Hotel |
| 星级 (xīngjí) | Star rating |
| 点评 (diǎnpíng), 评分 | Guest review, review score |
| 入住 / 离店 | Check-in / check-out |
| 含早餐 / 免费取消 | Breakfast included / free cancellation |
| 预付 / 到店付 | Prepay online / pay at the hotel |
| 房型 (fángxíng) | Room type |
| 商圈 (shāngquān) | Business or shopping district; Trip.com's area (`zone`) |
| 海外酒店 / 国内酒店 | Overseas / domestic hotels (`isOverseas`) |
| 民宿, 青年旅舍, 度假村 | Homestay, hostel, resort (`hotelCategory`) |
| WGS-84, GCJ-02, BD-09 | Coordinate systems: GPS standard, Chinese offset grid, Baidu grid |

### Is it legal to scrape Trip.com?

The Actor reads information that Trip.com shows to every visitor without a login; it bypasses no account or paid area. Whether using the data is lawful depends on what you do with it and where you are. Practical rules: do not republish Trip.com's photos or review texts as your own content (copyright); treat reviewer names and countries as personal data under the GDPR, the PIPL and similar laws, with a lawful basis and retention limits; hotel contact details suit B2B outreach but anti-spam and data-protection rules still apply; read Trip.com's terms of use and keep request rates reasonable. This is information, not legal advice.

### Changelog

- **1.0 (2026-10-29).** First release: destinations and hotel links, dates, guests, currency and language, six sort orders, filters, hotel pages, room types and rates, guest reviews, `fillGaps`, `onlyAvailable`, re-asking of false last pages, route ladder (direct, residential, datacenter), a `SUMMARY` record per run and a clean stop at "Maximum cost per run".

### Support

Questions, a destination that does not resolve, a field you miss: open an issue on the Actor's Issues tab in the Apify Store. We reply within 24 hours. Include the run link and your input JSON; for bug reports the `SUMMARY` record helps most.

# Changelog

This Actor's version history is a separate document: https://apify.com/logiover/trip-com-scraper/changelog.md

# Actor input Schema

## `destinations` (type: `array`):

Where to look for hotels, as you would type it into Trip.com: a city ("Tokyo", "Bangkok", "Shanghai"), an area or district ("Shibuya", "Sukhumvit"), a landmark or metro station ("Shibuya Station", "Marina Bay Sands"). Trip.com hotel list links (…/hotels/list?city=228…) and city IDs ("cityId:228") work too. Each destination is read to the end of its list unless a limit stops it.

## `checkInDate` (type: `string`):

YYYY-MM-DD, or +N for N days from the day of the run (e.g. +14 — handy for scheduled runs). Empty = 7 days from today, so a saved task never goes stale.

## `checkOutDate` (type: `string`):

YYYY-MM-DD or +N. Empty = check-in + "Nights".

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

Length of stay when no check-out date is given (1–30). Prices come per room per night and as a total for the stay.

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

Number of rooms (1–8). The nightly price is per room.

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

Number of adult guests in total (1–10).

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

Number of children (0–6). Give their ages below; a child without an age counts as 8.

## `childrenAges` (type: `array`):

One age per child, 0–17 (e.g. 4 and 9). Trip.com prices family rooms and child policies by age.

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

Currency of every price in the output (Trip.com converts at its own rate; the property's own currency is reported with room rates).

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

Language of hotel names, areas, rating words, policies and amenities. Hotel names in the local script come with the English name next to them; Trip.com's mainland-China site (zh-CN) is a different product and is not served here.

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

Which hotels come first (the "rank" column). The four stable orders (reviews, price, star rating, distance) are the ones to read a whole city with; Trip.com's own "recommended" order mixes in sponsored hotels and reshuffles between pages, so it is best for small top-N pulls.

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

Stop after this many unique hotels across all destinations and links. 0 = no limit (every hotel Trip.com lists — Shanghai has ~9,400, Tokyo ~6,900, Bangkok ~5,000). Big runs need a big enough "Maximum cost per run".

## `maxItemsPerDestination` (type: `integer`):

Optional cap per destination, so one big city does not take the whole "Max hotels". 0 = no per-destination limit.

## `fillGaps` (type: `boolean`):

After a destination's list has been read to its end, read it once more in another order (lowest price first, or highest price first when lowest price is your order) and add the hotels the first pass missed. Trip.com shuffles hotels with equal scores or prices between pages, so one pass can miss a few percent of a big city (measured on Tokyo: 3 % to 10 % depending on the order). Takes about as long as the first pass; only new hotels are saved and charged.

## `onlyAvailable` (type: `boolean`):

Trip.com also lists hotels that are sold out for your dates and guests (no price, tagged "Sold out"; they sit mostly at the end of the list). Turn this on to save only hotels that have a nightly price. Skipped hotels are not saved and not charged.

## `starRatings` (type: `array`):

Only hotels of these star classes (Trip.com's own star or diamond rating). Empty = any.

## `minGuestRating` (type: `string`):

Only hotels rated at least this on Trip.com's 10-point guest score.

## `minPrice` (type: `integer`):

Only hotels from this nightly price (per room, before taxes and fees), in the chosen currency. 0 = no minimum.

## `maxPrice` (type: `integer`):

Only hotels up to this nightly price (per room, before taxes and fees), in the chosen currency. 0 = no maximum.

## `freeCancellation` (type: `boolean`):

Only hotels with at least one free-cancellation rate for your dates.

## `breakfastIncluded` (type: `boolean`):

Only hotels with a rate that includes breakfast.

## `bedTypes` (type: `array`):

Only hotels with rooms of these bed types. Empty = any.

## `paymentType` (type: `string`):

Only hotels offering this payment option.

## `includeDetails` (type: `boolean`):

Adds the hotel's local-language name, phone, full street address, transit note, nearby places with distances, opening year, number of rooms, description, check-in/out times, child, pet, deposit, breakfast and age policies, the full amenity list by category, popular amenities and more photos. One extra page per hotel, included in the price.

## `includeRooms` (type: `boolean`):

Adds every room type (bed, size, floor, window, smoking, Wi-Fi, facilities, photos) with every rate Trip.com sells for your dates: price per night, total with taxes, taxes and fees, original price, discount labels, meal plan, cancellation terms, payment option, instant confirmation, rooms left and the price in the property's own currency. One extra request per hotel, included in the price.

## `maxReviewsPerHotel` (type: `integer`):

Adds up to this many guest reviews per hotel (text, date, stay date, overall and sub-ratings, traveller type, room, country, photos, the hotel's reply). 0 = no reviews. 10 reviews = one request.

## `reviewsSort` (type: `string`):

Which reviews come first when "Reviews per hotel" is set.

## `hotelUrls` (type: `array`):

Optional: specific hotels — Trip.com hotel links (https://www.trip.com/hotels/detail/?hotelId=72926277… or the SEO form …/shanghai-hotel-detail-72926277/…) or hotel IDs (the "hotelId" column of an earlier run). Each comes back with its price for your dates plus the hotel page fields; ideal for daily price tracking.

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

Used only as a fallback. The scraper talks to Trip.com over a direct connection first (no proxy cost); if Trip.com refuses it, it switches to the proxy chosen here (or Apify's residential pool when none is chosen) and then to the datacenter pool.

## Actor input object example

```json
{
  "destinations": [
    "Shanghai"
  ],
  "nights": 1,
  "rooms": 1,
  "adults": 2,
  "children": 0,
  "childrenAges": [],
  "currency": "USD",
  "language": "en-XX",
  "sortBy": "top_reviewed",
  "maxItems": 20,
  "maxItemsPerDestination": 0,
  "fillGaps": false,
  "onlyAvailable": false,
  "starRatings": [],
  "minGuestRating": "",
  "minPrice": 0,
  "maxPrice": 0,
  "freeCancellation": false,
  "breakfastIncluded": false,
  "bedTypes": [],
  "paymentType": "",
  "includeDetails": false,
  "includeRooms": false,
  "maxReviewsPerHotel": 0,
  "reviewsSort": "most_recent",
  "hotelUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All hotels collected in this run.

# 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 = {
    "destinations": [
        "Shanghai"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("logiover/trip-com-scraper").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 = {
    "destinations": ["Shanghai"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("logiover/trip-com-scraper").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 '{
  "destinations": [
    "Shanghai"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call logiover/trip-com-scraper --silent --output-dataset

```

## MCP server setup

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

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/fmf8wQ07njPnvAqIn/builds/ABQd0O32hjm8LNyKb/openapi.json
