# Trip.Com Review Scraper ⭐️ (`mrdoe/trip-com-review-scraper`) Actor

Extract guest reviews from Trip.com hotel pages anonymously — no login needed. Get rating, full review text, reviewer name and region, stay date, room type and travel type for any hotel by URL or ID. Batch multiple hotels for voice-of-customer or competitor research, one start fee per run.

- **URL**: https://apify.com/mrdoe/trip-com-review-scraper.md
- **Developed by:** [MrDoe](https://apify.com/mrdoe) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### What does Trip.com Review Scraper do?

**Trip.com Review Scraper** extracts guest reviews from [Trip.com](https://www.trip.com) hotel pages - rating, review text, reviewer name and region, stay date, room type, travel type, and language - **anonymously, no login, no Trip.com account, no API key**.

### Why use this Actor?

- **Voice-of-customer research** - pull real review text and ratings for any Trip.com hotel listing you have a URL or ID for.
- **Competitor monitoring** - track what guests say about a competing property without ever logging in.
- **Batch, one start fee** - pass a list of hotels and one run covers all of them.

### How to use it

1. Fill `hotel` with a Trip.com hotel URL (e.g. `https://www.trip.com/hotels/shanghai-hotel-detail-431900/...`) or a bare numeric hotel ID (e.g. `431900`) - or `hotels` for a batch.
2. Optionally set `maxItems` (reviews per hotel).
3. Click **Start**.

`hotels` wins over `hotel` when filled; duplicates and blanks are dropped automatically. **A direct hotel URL or numeric ID is the reliable input path** - grab either from the hotel's own Trip.com page. Free-text hotel names are also accepted and routed through Trip.com's own hotel-list search first, but live-testing found that search step does not reliably resolve a name to a hotel anonymously (Trip.com's `keyword=` list-page parameter did not return matching results in testing) - a name search will often come back as a `not_found` row. Use a URL or ID whenever you have one.

### Input

| Field                  | Type           | Description                                                                                                                                                       |
| ---------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hotel` / `hotels`     | string / array | A Trip.com hotel detail URL, a bare numeric hotel ID, or a hotel name. At least one is required.                                                                  |
| `maxItems`             | integer        | Caps the number of review rows returned **per hotel** (default 20). The first 10 review rows in a run are always free - see [Pricing](#pricing).                  |
| `checkIn` / `checkOut` | string         | YYYY-MM-DD. Only affects the availability context the page renders with, not which reviews are shown. Default: a rolling 2-night stay starting 2 days from today. |
| `proxyConfiguration`   | object         | A residential proxy is strongly recommended - Trip.com's bot detection is more aggressive on datacenter IPs.                                                      |

### Output

One flat row per review, with the hotel's ID/name/URL repeated on every row for convenience. `status` is `success` for a review row, `no_reviews` when the page loaded but no review data came back, `not_found` when a hotel-name search matched nothing, or `error` for a malformed response.

```json
{
    "hotelInput": "https://www.trip.com/hotels/shanghai-hotel-detail-431900/meta-tree-hotel-people-s-square-city-center-in-shanghai/",
    "hotelId": "431900",
    "hotelName": "Meta Tree Hotel, People's Square, City Center In Shanghai",
    "hotelUrl": "https://www.trip.com/hotels/shanghai-hotel-detail-431900/meta-tree-hotel-people-s-square-city-center-in-shanghai/",
    "reviewId": "2078736922",
    "reviewerName": "Anonymous User",
    "reviewerRegion": "Malaysia",
    "rating": 10,
    "ratingLabel": "Outstanding",
    "reviewText": "It was a short and meaningful stay. This hotel was a very strategic place to stay...",
    "reviewDate": "2026-08-25 14:05:56",
    "stayDate": "2026-08-01 00:00:00",
    "roomType": "Deluxe Queen Room",
    "travelType": "Traveling with friends",
    "language": "en",
    "recommend": true,
    "usefulCount": 0,
    "imageCount": 3,
    "status": "success"
}
```

**Note:** Trip.com rates on a **0-10 scale**, not 0-5.

### Pricing

This Actor uses pay-per-event pricing - one small run-start charge, then a per-row charge for each review returned. See the **Pricing** tab for current rates. **The first 10 review rows in a run are always free**, regardless of how many hotels you pass in; every row after that is charged normally. `no_reviews`/`not_found`/`error` rows are never charged. Use `maxItems` to cap per-hotel spend on a large batch.

### How this works (and why a headed browser)

Live-verified (2026-08-28): Trip.com's hotel-review API (`restapi/soa2/34308/getHotelCommentInfo`) returns an HTTP 430 "whaleguard block" when called directly - both a plain curl replay of a captured request and a synthetic in-page `fetch()` call were blocked. **It is not blocked when the request is the one the hotel-detail page's own JavaScript makes as part of a normal page load.** This Actor drives a real, headed (non-headless) Chromium browser to the hotel page and intercepts that one genuine, page-triggered network call to read the review data straight out of it - it does not replay or forge the request.

A second, unrelated wrinkle: the *rendered* hotel-detail page itself bounces an anonymous headed-browser session to a Trip.com sign-in wall almost immediately after loading (verified across multiple hotels, both via a real click-through from a search-results page and via direct navigation to the canonical hotel URL). This happens regardless - the review API call already completed and returned real data *before* that redirect lands, so it doesn't block extraction, but it does mean this Actor cannot rely on further on-page interaction (scrolling, clicking "load more") to pull additional pages of reviews the way a signed-in user could.

As a best-effort improvement, before letting that one real request through, the Actor raises its `pageSize` parameter to your requested `maxItems` (live-verified: a modified real request returned 25 reviews in one call vs. the site's own default of 10, still HTTP 200/real data). If that modified request errors or stalls, the Actor aborts it cleanly rather than risk a stuck run - the hotel then comes back as `no_reviews` for that run instead of partial/garbage data.

### Limitations - please read before buying

- **This is one real batch per hotel, not full pagination.** There is no confirmed, anonymous way to page past what a single real page-load request returns. `maxItems` above roughly 30-50 is unlikely to return more than Trip.com's own API hands back in that one call for a given hotel.
- Because the review API call happens as a side effect of page load rather than the page fully rendering, **hotel name/rating/address metadata beyond `hotelName`** (parsed from the page `<title>`) is not extracted in this version - it's a review-per-row dataset, not a hotel-profile dataset. Pair it with a hotel-detail Actor if you need full property data.
- **Hotel-name input is unreliable.** It routes through Trip.com's own hotel-list search first, and live-testing (2026-08-28) found the anonymous `keyword=` list-page parameter did not return matching results - a name search will typically come back as a `not_found` row rather than resolving. Use a direct hotel URL or numeric ID, which skip this step entirely and were the input paths verified end-to-end.
- Only the reviews Trip.com's own review widget serves to an anonymous visitor's real page load are available - if a hotel genuinely has none loaded that way, that's a `no_reviews` row, not a bug.
- `hotelName` is read from the page's `<title>` at whatever moment the sign-in redirect happens to land, which varies by network conditions (residential-proxy platform runs observed it landing sooner, before the title populates) - it can legitimately come back `null` even on a fully successful run with real reviews. Treat it as a best-effort convenience field, not a guaranteed one.
- This Actor requires a real, headed Chromium browser (see [How this works](#how-this-works-and-why-a-headed-browser)) - it's slower and heavier than a plain HTTP-based scraper by necessity.
- Trip.com's page/API structure drifts over time; a large redesign may need an update.

### FAQ

**Why isn't this the full review list?** See [Limitations](#limitations---please-read-before-buying) above - Trip.com's anonymous hotel-detail page only exposes one real batch of reviews per page load, and further pagination requires a signed-in session this Actor never asks for.

**Do I need a Trip.com account or API key?** No - it runs entirely against Trip.com's public, logged-out hotel pages.

**Why is the rating out of 10, not 5?** That's Trip.com's own scale - this Actor passes it through unchanged rather than rescaling it.

**A run returns a `no_reviews` row - why?** The one real page-load request this Actor intercepts didn't return review data for that hotel in that run - try again, or verify the hotel/URL is correct.

### Disclaimer

This Actor is an independent tool, not affiliated with or endorsed by Trip.com. It only accesses data Trip.com serves publicly to anonymous visitors. Use it in compliance with Trip.com's Terms of Use and applicable law in your jurisdiction. Found a bug or have a feature request? Use the Issues tab on this Actor's page.

# Actor input Schema

## `hotel` (type: `string`):

A Trip.com hotel detail page URL (e.g. "https://www.trip.com/hotels/shanghai-hotel-detail-431900/...") or a bare numeric Trip.com hotel ID (e.g. "431900") - the reliable inputs. A free-text hotel name is also accepted but is best-effort only (Trip.com's anonymous keyword search does not reliably resolve names in testing). Defaults to a demo hotel if left blank.

## `hotels` (type: `array`):

Many hotel URLs, numeric IDs, or names in one run. Wins over "hotel" when filled.

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

Caps the number of review rows returned per hotel. Trip.com's own review widget serves reviews in a single batch per anonymous page load (no confirmed infinite pagination) - values above ~30-50 are unlikely to return more than the site itself hands back in that batch. The first 10 review rows in a run are always free.

## `checkIn` (type: `string`):

Only affects the availability context Trip.com renders the page with, not which reviews are shown. Defaults to 2 days from today if left blank.

## `checkOut` (type: `string`):

Only affects the availability context Trip.com renders the page with, not which reviews are shown. Defaults to a 2-night stay from check-in if left blank.

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

A residential proxy is strongly recommended - Trip.com applies bot-detection to hotel detail pages that is more aggressive on datacenter IPs.

## Actor input object example

```json
{
  "hotel": "https://www.trip.com/hotels/shanghai-hotel-detail-431900/meta-tree-hotel-people-s-square-city-center-in-shanghai/",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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 = {
    "hotel": "https://www.trip.com/hotels/shanghai-hotel-detail-431900/meta-tree-hotel-people-s-square-city-center-in-shanghai/",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrdoe/trip-com-review-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 = {
    "hotel": "https://www.trip.com/hotels/shanghai-hotel-detail-431900/meta-tree-hotel-people-s-square-city-center-in-shanghai/",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("mrdoe/trip-com-review-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 '{
  "hotel": "https://www.trip.com/hotels/shanghai-hotel-detail-431900/meta-tree-hotel-people-s-square-city-center-in-shanghai/",
  "maxItems": 20
}' |
apify call mrdoe/trip-com-review-scraper --silent --output-dataset

```

## MCP server setup

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