# Trip.com Reviews Scraper - New Hotel Reviews Monitor (`neverempty/trip-com-reviews-scraper`) Actor

For hotel managers, revenue teams and review-monitoring tools: review text, rating, date, trip type, room, language, English translation and hotel reply from Trip.com hotel pages. 5 of 5 reviews matched the hotel page in a browser. Monitoring returns only new reviews.

- **URL**: https://apify.com/neverempty/trip-com-reviews-scraper.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Travel, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 review returneds

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 Reviews Scraper - New Hotel Reviews Monitor

For hotel managers, revenue teams and review-monitoring tools: review text, rating, date, trip type, room, language, English translation and hotel reply from Trip.com hotel pages. In a check on 2026-09-21, 5 of 5 reviews matched the hotel page opened in a browser, for each of two hotels (review text and posting date of each review). Put many hotels in one run, set it on a schedule in monitoring mode, and you get back only the reviews you have not received yet - no diffing on your side.

**What one run can and cannot get.** Each hotel is one request for its Trip.com hotel page, and that page carries the reviews Trip.com shows first - about 10 per hotel, in Trip.com's "Most relevant" order, not newest first. How recent they are depends on the hotel: on 2026-09-21, Marina Bay Sands showed 10 reviews posted since 18 July 2026 and The Venetian Macao 10 posted in the previous 6 days, while Park Hyatt Tokyo showed 6 reviews from 2023-2024 among its 10, and the newest one shown for Burj Al Arab was from May 2026. This Actor does not page back through a hotel's full review history, and a new review is returned only once Trip.com puts it on the hotel page. It is built for watching hotels over time: run it on a schedule in monitoring mode and every review that appears on the page is returned once.

Unofficial. Public data only.

Export as JSON, CSV or Excel.

### What you get

- **One row per review** shown on each hotel page: review ID, posting date and time, stay month, overall score out of 10 and the four category scores (location, amenities, service, cleanliness), review text and its language, the English translation when Trip.com shows one, trip type, room, the reviewer's public display name and country, photo count, helpful votes and the hotel's reply with its date.
- **Hotel context on every row**: Trip.com hotel ID, hotel name, city, the hotel's total review count and overall rating on Trip.com.
- **Many hotels in one run** (`hotelUrls`): paste hotel page addresses from any Trip.com country site, or plain hotel IDs. The same hotel written two ways is read once.
- **Monitoring mode** (`monitoringMode`): only reviews this watch has not returned before. The first run for a hotel returns every review on its page.
- **No failed runs for "nothing found".** A hotel with no reviews, an unknown hotel ID, an unreadable or refused page, a spending limit and "no new reviews" each come back as a free row that says why.

### Input

| Field | What it does |
|---|---|
| `hotelUrls` | Trip.com hotel pages, one per entry, for example `https://www.trip.com/hotels/singapore-hotel-detail-687592/marina-bay-sands/`, or a plain hotel ID such as `687592`. Addresses from other Trip.com country sites (`us.trip.com`, `uk.trip.com`, ...) work too; the page is always read from www.trip.com in English. Up to 500 hotels per run. Lines that are not Trip.com hotel pages are skipped and listed in a free row. |
| `monitoringMode` | Return only reviews this watch has not returned before. |
| `resetMonitoringState` | Forget which reviews were already returned for the hotels in this run; the next monitoring run returns every review on their pages again. |

### Output

```json
{
  "source": "trip.com",
  "status": "ok",
  "reviewId": "2106132610",
  "hotelId": "375126",
  "hotelName": "5L Hotel",
  "hotelCity": "Beijing",
  "hotelUrl": "https://www.trip.com/hotels/beijing-hotel-detail-375126/5l-hotel/",
  "requestedAs": "https://www.trip.com/hotels/beijing-hotel-detail-375126/5l-hotel/",
  "publishedAt": "2026-09-17T15:21:25",
  "publishedDate": "2026-09-17",
  "stayMonth": "2026-09",
  "rating": 5.5,
  "ratingScale": 10,
  "ratingLocation": 8,
  "ratingAmenities": 4,
  "ratingService": 6,
  "ratingCleanliness": 4,
  "text": "The room was very old. TV wasn't working well. There was no telephone in the room, so I could only reached front desk by using my cell phone to call. Toilet bowl flushing system was faulty.",
  "language": "en",
  "translatedText": null,
  "translatedLanguage": null,
  "tripType": "Traveling with friends",
  "roomName": "Apartment Of Twin Beds",
  "reviewerName": "YSTT",
  "reviewerCountry": "Singapore",
  "photoCount": 3,
  "helpfulCount": 0,
  "hotelResponse": "Dear Guest, thank you for sharing your feedback with us. We're truly sorry that your stay did not meet your expectations. ...",
  "hotelResponseDate": "2026-09-17",
  "reviewPlatform": "Trip.com",
  "sourceName": "English",
  "positionOnPage": 1,
  "hotelReviewCount": 2321,
  "hotelRating": 9,
  "firstCheck": true,
  "scrapedAt": "2026-09-21T11:30:00.000Z"
}
```

| Column | Meaning |
|---|---|
| `reviewId` | Trip.com's own ID for the review. Monitoring remembers these. |
| `hotelId` / `hotelName` / `hotelCity` | The hotel the page belongs to, as the page names it. A page that names a different hotel ID than the one you asked for is not sold; it comes back as an `unreadable` row. |
| `hotelUrl` / `requestedAs` | The page that was read, and the line you gave. |
| `publishedAt` / `publishedDate` | When the review was posted, as Trip.com gives it. Trip.com does not state a time zone, so no zone is added (`publishedDate` is the date the page shows as "Posted"). |
| `stayMonth` | Month of the stay. Trip.com gives only the month. |
| `rating` / `ratingScale` | Overall score and its scale (10). |
| `ratingLocation` / `ratingAmenities` / `ratingService` / `ratingCleanliness` | Category scores, labelled as Trip.com labels them. `null` when the reviewer gave none. |
| `text` / `language` | The review as written, and its language code. |
| `translatedText` / `translatedLanguage` | Trip.com's own machine translation, when the page carries one (the page marks it "Translation provided by AI"). |
| `tripType` / `roomName` | Trip type and room as shown on the review. |
| `reviewerName` / `reviewerCountry` | The reviewer's public display name and country as shown on the page ("Guest User" and "Anonymous User" are Trip.com's own labels). Nothing else about the reviewer is returned. |
| `photoCount` / `helpfulCount` | Photos attached to the review, and its helpful votes. |
| `hotelResponse` / `hotelResponseDate` | The hotel's reply and its date, or `null`. |
| `reviewPlatform` / `sourceName` | `Trip.com` or `Ctrip` (Trip.com's Chinese sister site, whose reviews Trip.com also shows); `null` for anything else, with Trip.com's raw label in `sourceName`. |
| `positionOnPage` | 1 = the first review on the hotel page. |
| `hotelReviewCount` / `hotelRating` | The hotel's total review count and overall rating on Trip.com at the time of the run. |
| `firstCheck` | Monitoring only: `true` when this watch had nothing remembered for the hotel yet, `false` for a review that appeared since. |

Rows that are not reviews are free and have `status` and `note` instead of review columns:

| `status` | Meaning |
|---|---|
| `no-reviews` | Trip.com shows no reviews for the hotel (its review count is 0). |
| `hotel-not-found` | Trip.com has no hotel page for this ID. |
| `unreadable` | The page could not be read, or it named another hotel. Nothing is guessed. |
| `blocked` | Trip.com refused the request (HTTP 403 or 429). The run stops there and lists the hotels not read; it does not try to get around the refusal. |
| `bad-input` | Nothing usable in `hotelUrls`, or some lines were skipped (they are listed). |
| `no-new-since-last-run` | Monitoring: no review on the pages is new since this watch last returned reviews. |
| `budget-reached` | The run reached the maximum total charge you set; the note says how many reviews and which hotels were not returned. |

### Monitoring on a schedule

1. Put your hotels in `hotelUrls`, turn on `monitoringMode`, and save it as a task.
2. Schedule the task, for example daily. (On 2026-09-21, the two hotels checked had 3 reviews each posted in the previous 14 days.)
3. Each run returns only reviews not returned before. The watch is remembered per hotel, so you can add or remove hotels at any time.

A review that appeared and left the page between two runs is not seen, because only the page is read. The more often the task runs, the smaller that gap.

Do not put the same hotel in two schedules that run at the same time: the memory of returned reviews is saved with a re-read and merge, but Apify's storage has no atomic update, so two runs finishing at the same moment can still both return the same new review.

### Pricing

- **Run start: $0.02 per run** on the free plan, down to $0.0146 per run on higher Apify plans (Bronze $0.0182, Silver $0.0164, Gold $0.0146). Charged once for every run that requests anything - including a run that finds no new reviews, and a run Trip.com refuses. It is charged before the first request, so a run whose maximum total charge has no room for the start fee plus one review row (in monitoring mode, plus one hotel check) requests nothing and is charged nothing. A run Apify restarts or moves is charged once.
- **Review row: $4 per 1,000** on the free plan, down to $3 per 1,000 on higher Apify plans. Only review rows are charged; every row with a `note` is free.
- **Monitoring check: $0.30 per 1,000** on the free plan, down to $0.22 per 1,000 on higher Apify plans: one per hotel page read and compared in monitoring mode, whether or not it has new reviews (pages that could not be read, unknown hotel IDs and refused requests are not charged). A hotel page is read only if your maximum total charge leaves room for its check and one review row.

### Notes

- Only the hotel page is read (`/hotels/...-hotel-detail-<id>/`). Trip.com's review API and `/review/` pages are disallowed in its robots.txt and are not used.
- Requests are spaced about 1.5 seconds apart. Server errors are retried twice; refusals are not retried.

# Actor input Schema

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

Trip.com hotel page addresses, one per entry, copied from the browser (any Trip.com country site works, for example us.trip.com or uk.trip.com), or plain Trip.com hotel IDs such as 687592. Each hotel is one page request and returns the reviews shown on that page (about 10, the ones Trip.com shows first). Up to 500 hotels per run.

## `monitoringMode` (type: `boolean`):

Return only reviews that this watch has not returned before. Each hotel page checked is charged the small check fee, and each new review is charged as a review row. The first run for a hotel returns every review in its page.

## `resetMonitoringState` (type: `boolean`):

Forget which reviews were already returned for the hotels in this run, so the next monitoring run returns every review in their pages again.

## Actor input object example

```json
{
  "hotelUrls": [
    "https://www.trip.com/hotels/singapore-hotel-detail-687592/marina-bay-sands/"
  ]
}
```

# Actor output Schema

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

One row per review shown on each Trip.com hotel page: review ID, date, stay month, overall and category ratings, review text, language, English translation, trip type, room, the reviewer's public display name and country, photo count, the hotel's reply, and the hotel's name, city, review count and rating. In monitoring mode, only reviews not returned before. Hotels with no reviews, unknown hotel IDs, unreadable or refused pages and runs that hit their maximum charge come back as free rows that say why.

# 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 = {
    "hotelUrls": [
        "https://www.trip.com/hotels/singapore-hotel-detail-687592/marina-bay-sands/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/trip-com-reviews-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 = { "hotelUrls": ["https://www.trip.com/hotels/singapore-hotel-detail-687592/marina-bay-sands/"] }

# Run the Actor and wait for it to finish
run = client.actor("neverempty/trip-com-reviews-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 '{
  "hotelUrls": [
    "https://www.trip.com/hotels/singapore-hotel-detail-687592/marina-bay-sands/"
  ]
}' |
apify call neverempty/trip-com-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/trip-com-reviews-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/w2BPgqs5UYy68HAAJ/builds/wW1PCDmYhVNfbQL97/openapi.json
