# Trip.com Attraction Products Scraper (`boncross/tripcom-attraction-products`) Actor

Scrape every product Trip.com sells for an attraction. Just add an attraction URL and get each ticket, pass and tour with its price, person types, sales count, first bookable date, cheapest date, tags, category, city and stock status. Track price changes between runs. $3.00 per 1,000 products.

- **URL**: https://apify.com/boncross/tripcom-attraction-products.md
- **Developed by:** [BonCross API](https://apify.com/boncross) (community)
- **Categories:** Travel
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 product-scrapeds

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 Attraction Products Scraper

### What is Trip.com Attraction Products Scraper?

Point Trip.com Attraction Products Scraper at an attraction and you get its whole shelf: each ticket, combo, pass and tour Trip.com sells for that place, priced, with how many have been sold. The Grand Palace in Bangkok had 18 products on 7 October 2026, from a $14.86 entry ticket bought 52,665 times to combos with river cruises and a Muay Thai ringside seat. You'd get all 18 from one pasted link.

What makes it worth picking:

- You see what sells. Trip.com publishes a sales count per product, and it's on the row. On a 71-product shelf we measured, 99% of products had one.
- The ticket terms are included in the price. Switch on "Include product details" for what's included and excluded, how to use the ticket and the booking notes. There's no extra charge for them.
- It remembers prices. Name a price memory and a scheduled run returns only the products whose price moved. The rest are free.
- Size doesn't slow it down. 150 attractions returned 2,323 products in 33.5 seconds.
- $3.00 per 1,000 products on the Free plan and $2.10 on Business, with proxy usage and platform usage included.

**BonCross Verified** means we tested this actor against the live site before release and kept the record:

- 19 of 19 live checks on its inputs and filters passed on 7 October 2026
- 14 attractions run the same day: 124 products, 3 error rows
- Charges matched the rows: 11 attractions, 124 products
- An attraction with nothing on sale gets an uncharged row saying so

It's the first step for most Trip.com ticket work. The product ids on its rows are what [Trip.com Attraction Availability & Prices](https://apify.com/boncross/tripcom-availability) takes to return dates, price per date and places left, and what [Trip.com Product Details Scraper](https://apify.com/boncross/tripcom-product-details) takes to return one tour's full record. If you'd sooner start from a keyword or a city than from an attraction, that's [Trip.com Things to Do Search](https://apify.com/boncross/tripcom-product-search). Visitor reviews of the attraction come from [Trip.com Attraction Reviews Scraper](https://apify.com/boncross/tripcom-reviews), and hotels from [Trip.com Hotel Search Scraper](https://apify.com/boncross/tripcom-hotel-search) and its siblings.

### What product data do you get?

| | |
|---|---|
| 🎟️ Product name | 🆔 Product id |
| 💵 Current price | 🏷️ List price |
| 💱 Currency | Discount amount and percent |
| 👤 Person types with prices | Ticket group |
| 🛒 Sales count | Yearly sales of the ticket group |
| 📅 First bookable date | Cheapest date |
| ✅ In stock | ↩️ Refundable |
| Tags | Payment mode |
| 🏛️ Attraction name and id | 🔗 Attraction link |
| 🏙️ City | Category |
| What is included and excluded | How to use the ticket |
| Booking notes (cut-off, ticketing time, conditions) | Other notes |
| 📈 Price change since last run | Product link |

### How to scrape Trip.com attraction products

1. [Create an Apify account](https://console.apify.com/sign-up). It's free.
2. Open [Trip.com Attraction Products Scraper](https://apify.com/boncross/tripcom-attraction-products).
3. On Trip.com, open the attraction's page and copy its address into Attractions.
4. Pick the currency you want prices in.
5. Press Start, and download the product list as Excel, CSV or JSON when it's done.

### ⬇️ Input

Paste attraction links, such as `https://www.trip.com/travel-guide/attraction/bangkok/the-grand-palace-77012`, or the bare id at the end of one (`77012`). Start URLs takes the same links in bulk, from a file, a Google Sheet or a remote list, and the two inputs are combined.

"Max products per attraction" limits each attraction separately: ten attractions at 50 each returns 500. "Maximum results for the whole run" limits the total, and nothing beyond it is fetched or charged for. Both are 0 by default, meaning the whole shelf.

Prices are quoted in the currency you choose (USD unless you change it). Product names and tags follow the locale.

#### The whole shelf of one attraction

```json
{
  "attractions": ["https://www.trip.com/travel-guide/attraction/bangkok/the-grand-palace-77012"],
  "currency": "USD"
}
```

#### The shelf with ticket terms, category and city

```json
{
  "attractions": ["https://www.trip.com/travel-guide/attraction/seoul/n-seoul-tower-83001"],
  "includeDetails": true,
  "maxDetailProducts": 50
}
```

#### Three attractions in one run, by id

```json
{
  "attractions": ["77012", "83001", "87338"],
  "currency": "USD",
  "maxProductsPerAttraction": 40
}
```

Those are the Grand Palace, N Seoul Tower and Burj Khalifa.

#### A daily price watch that returns only what moved

```json
{
  "attractions": ["https://www.trip.com/travel-guide/attraction/seoul/n-seoul-tower-83001"],
  "priceStoreName": "seoul-tower-prices",
  "onlyNewOrChanged": true
}
```

| Field | Notes |
|---|---|
| `attractions`, `startUrls` | Attraction links or bare ids, pasted or loaded in bulk. |
| `maxProductsPerAttraction`, `maxItems` | The per-attraction cap and the run-wide cap. Both default to `0`, no limit. |
| `includeDetails`, `maxDetailProducts` | Adds category, city, stock flags and the ticket terms, on up to this many products per attraction (default `20`). `includeDetails` is `false` by default. |
| `currency` | ISO code, default `USD`. |
| `locale` | Language of product names and tags, default `en-XX`. |
| `priceStoreName`, `onlyNewOrChanged` | The price memory, and the switch that returns only products whose price moved. |
| `includeRawData` | Attaches Trip.com's unparsed product record to each row. Default `false`. |
| `delayMs`, `maxConcurrency` | Pacing. Defaults `700` and `8`. |

#### For developers

- `includeDetails` costs time, not money: it has no charge event. `maxDetailProducts` (default 20, up to 500) caps how many products per attraction get the extra lookup. The detail columns appear only on the products inside that cap.
- `priceStoreName` names a key-value store holding the last price per product. Rows then have `previousPrice`, `previousScrapedAt`, `priceChange` and `priceChangePct`. `onlyNewOrChanged` needs the store.
- `maxItems` doesn't count rows reporting an input the actor couldn't resolve. Those rows are never charged.
- `delayMs` (default 700, up to 10,000) is the pause between calls. `maxConcurrency` (default 8, from 1 to 8) is how many requests run at once, and 8 is the fastest level we measured clean. Go lower only when a run reports refusals or errors.
- Rows are saved as they arrive. If the platform interrupts and restarts a run, it resumes where it stopped and no product is saved or charged twice.

### ⬆️ Output

One row per product. This is N Seoul Tower's best seller, from a run on 7 October 2026 with product details on. Long texts are shortened with "…".

```json
{
  "input": "https://www.trip.com/travel-guide/attraction/seoul/n-seoul-tower-83001",
  "id": "109937038-109937040-Observatory Ticket",
  "productId": "109937038",
  "url": "https://www.trip.com/things-to-do/detail/109937038/",
  "poiId": "83001",
  "attractionName": "N Seoul Tower",
  "name": "Observatory Ticket [Individual (Non-Korean Nationality)]",
  "resourceId": "109937040",
  "relatedProductIds": ["109937038"],
  "price": 15.32,
  "priceText": "15.32",
  "priceListed": 21.67,
  "currency": "USD",
  "discountAmount": null,
  "discountPct": 29,
  "minPriceDate": "2026-10-08",
  "firstBookingDate": "2026-10-08",
  "ticketType": "Individual",
  "isAvailable": true,
  "isSoldOut": false,
  "stockStatus": 1,
  "isRefundable": false,
  "tags": ["Up to US$6.35 off", "Trip.com discount", "Official partner", "Immediate access", "Valid until December 31, 2027", "Non-refundable", "Ticket collection required"],
  "payMode": "P",
  "salesCount": 39470,
  "advanceBookingDays": 0,
  "ticketGroupName": "Observatory Ticket",
  "ticketGroupYearlySales": 97735,
  "ticketOptions": [
    { "id": "758407", "name": "Individual", "code": "daxtj", "price": 15.32, "currency": "USD" },
    { "id": "551910", "name": "Infant", "code": "yingyrp", "price": 0, "currency": "USD" }
  ],
  "attractionUrl": "https://www.trip.com/travel-guide/attraction/seoul/n-seoul-tower-83001",
  "spotId": "50023",
  "categoryName": "Individual Attraction/Activity Ticket",
  "categoryId": "392",
  "cityName": "Seoul",
  "hasInventory": true,
  "productFlags": ["hasInventory", "active", "online", "translate", "supportGiftCard", "systemTranslate"],
  "inclusions": ["Observatory Ticket", "About this Product", "· What's included: N Seoul Tower Observatory ticket. Digital telescopes and audio guides are available for an additional fee"],
  "exclusions": ["Other personal expenses"],
  "howToUse": "Ticket collection time & location 105 Namsan Mountain Park Road, Yongsan-gu, Seoul (Yongsan-dong 2-ga), redeem your tickets at the self-service ticket machine on the B1 level of the observation deck…",
  "bookingNotes": [
    { "code": "ReadyToUse", "title": "Immediate access", "text": "Must be purchased [by 22:00 (local time) on the date of use]. Effective immediately after booking is confirmed…" },
    { "code": "TicketSpeed", "title": "Ticketing time", "text": "Tickets are issued in 1 seconds on average" },
    { "code": "NonRefundable", "title": "Non-refundable", "text": "Please note that the booking cannot be canceled once it is confirmed…" }
  ],
  "otherNotes": [
    { "code": "GiftCard", "title": "Gift card", "text": "Gift cards can be used for payment. Details will be listed on the payment page." }
  ],
  "previousPrice": null,
  "previousScrapedAt": null,
  "priceChange": null,
  "priceChangePct": null,
  "scrapedAt": "2026-10-07T20:26:55.391Z"
}
```

The full row has five booking notes and three other notes. Reading the columns:

- `id` joins the product, the shelf entry and its name, because one product can sit on the shelf under more than one ticket.
- `discountAmount` is Trip.com's promotion amount and `discountPct` its own percentage against `priceListed`. Trip.com publishes the two separately and they don't always agree, as you can see above.
- `ticketGroupYearlySales` is the figure for the ticket group, not this product. It's often 0 where the product itself has sales.
- `isRefundable` comes from the card's tags: "Non-refundable" is false, "Cancel anytime" is true, and "Conditional cancellation" is left empty.
- `categoryName`, `categoryId`, `cityName`, `hasInventory`, `productFlags` and the ticket terms appear only with "Include product details" on, and only on the products its cap covers.
- `inclusions` and `exclusions` are lists of lines as Trip.com publishes them. `howToUse` is text. `bookingNotes` and `otherNotes` are lists of `{code, title, text}`, where `code` is Trip.com's own item code (`BookingDate`, `ReadyToUse`, `TicketSpeed`, `NonRefundable`, `ApplicableConditions` …) and is the same in each language.

On 20 products at two attractions, measured 4 October 2026, inclusions, how-to-use, booking notes and other notes were on every product. Exclusions were on the few that list any.

### How much does it cost to scrape Trip.com attraction products?

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, per run | $0.002 | $0.002 | $0.002 | $0.002 |
| `attraction-resolved`, per attraction read | $0.002 | $0.002 | $0.002 | $0.002 |
| `product-scraped`, per product | $0.003 | $0.0027 | $0.0024 | $0.0021 |

Enterprise plans pay the Business price.

**$3.00 per 1,000 products** on the Free plan, $2.10 on Business. There's nothing else on the bill: no proxy to rent, and platform usage is in the price.

If Trip.com lists a product twice, you're billed once. With "Only new or changed" on, products whose price didn't move are free. The product details are free too.

An attraction that can't be read, or has nothing on sale, comes back as one row with an `error` that says what happened and what to do about it. You pay nothing for that row, and no attraction fee either.

- The Grand Palace's 18 products: $0.002 + $0.002 + 18 × $0.003 = **$0.058** ($0.0418 on Business).
- A 71-product shelf: $0.002 + $0.002 + 71 × $0.003 = **$0.217** ($0.153 on Business).
- A daily price watch on one attraction where five products move: $0.002 + $0.002 + 5 × $0.003 = **$0.019** ($0.0145 on Business).

Apify's Free plan gives you $5 of credits each month. With this actor that's about 86 attractions the size of the Grand Palace's shelf, or about 1,500 products.

### How many products can you get, and how fast?

Three runs each on 2 October 2026, timed from start to finish:

| Run | Rows | Time | Cost at the Free-plan price |
|---|---|---|---|
| One attraction, first 8 products | 8 | 4.6 to 5.9 s | $0.028 |
| Two attractions (one with nothing on sale), category details on 10 products | 30 + 1 notice | 5.7 to 6.7 s | $0.094 |
| 150 attractions, every product | 2,323 + 5 notices | 33.5 s | $7.261 |

On a large run that works out at about 4,000 products a minute, or roughly 15,000 attractions an hour. A big attraction takes no longer than a small one.

How many rows you get depends on the attraction. The 71-product shelf mentioned above was measured on 11 September 2026, with a price on all 71. On 7 October 2026 the Grand Palace had 18 products and N Seoul Tower had 5.

### Put it on a schedule, or call it from code

A shelf changes: products appear, prices move, a combo gets pulled. An Apify Schedule with a price memory turns this actor into a daily diff of one attraction, or of many. For one-off calls, `POST https://api.apify.com/v2/acts/boncross~tripcom-attraction-products/run-sync-get-dataset-items` with the input JSON returns the product list in the response, and `apify-client` on npm or PyPI handles the longer runs. Through the Apify MCP server (`mcp.apify.com`) an AI agent sees it as the tool `boncross/tripcom-attraction-products` and can be handed an attraction link.

### What it doesn't do

- You get the headline "from" price of each product. For the price on a given date, time slot and ticket type, run the availability actor on the product id.
- You won't get a product image or coordinates from the shelf. City and category come with "Include product details". A description, photos and an itinerary don't.
- Trip.com publishes the list price as zero on many products. `priceListed` and the discount fields are empty for those.
- `isRefundable` is read from English tags. In other locales it's left empty, not guessed.
- An attraction can have a free-entry note on its shelf. It's returned as a row with no product id or price.
- An attraction with nothing on sale returns a row saying so. Trip.com doesn't say whether it's suspended or never sold tickets.
- Trip.com takes a product it can't sell off the shelf. You won't find sold-out products listed with a flag.

### FAQ

#### How is this different from the availability actor?

This one lists what an attraction sells, with one headline price per product. The availability actor takes a single product and returns its booking calendar: each date, time slot and ticket type with its own price and places left.

#### Can I tell which tickets are popular?

`salesCount` is the number Trip.com publishes for the product, and `ticketGroupYearlySales` is the yearly figure for its ticket group. Sort on the first and the best sellers are at the top.

#### How do I track price changes on a shelf?

Give the price memory a name and schedule the run. From the second run on, rows show the previous price and the change. Add "Only new or changed" if you want just the products that moved, which also means you pay only for those.

#### Why are the discount columns empty on most rows?

Because Trip.com gives no list price for those products. Where it does, you get `priceListed` and its percentage.

#### Can I get prices in my own currency, or names in another language?

Set Currency to any ISO code Trip.com quotes. Set Locale for the names and tags. One caveat: outside English, `isRefundable` is empty.

#### What do I get for an attraction with nothing on sale?

A row that says no products were returned. You aren't charged the attraction fee for it.

#### Do I need proxies or a Trip.com account?

No account, no proxy, and no proxy fee on top of the price per product.

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

The actor reads the public product listings Trip.com shows any visitor who isn't signed in. Scraping public data is generally legal. You're responsible for how you use it, and for following Trip.com's terms and the law that applies to you.

### More from BonCross

- [Trip.com Attraction Availability & Prices](https://apify.com/boncross/tripcom-availability): Trip.com attraction availability and prices.
- [Trip.com Hotel Details Scraper](https://apify.com/boncross/tripcom-hotel-details): The full Trip.com record for any hotel, with its guest reviews.
- [Trip.com Hotel Search Scraper](https://apify.com/boncross/tripcom-hotel-search): Every hotel Trip.com lists for a destination and your dates.
- [Trip.com Product Details Scraper](https://apify.com/boncross/tripcom-product-details): Trip.com tour and activity details.
- [Trip.com Things to Do Search](https://apify.com/boncross/tripcom-product-search): Search Trip.com's things-to-do catalogue by keyword, city or attraction.
- [Trip.com Attraction Reviews Scraper](https://apify.com/boncross/tripcom-reviews): Trip.com reviews for any attraction.

### Your feedback

Missing a product you can see on the attraction's page, or a field you'd like on the row? Report it on the Issues tab in Apify Console and include the attraction link. BonCross reads every issue, and fixes go out as new builds.

# Changelog

This Actor's version history is a separate document: https://apify.com/boncross/tripcom-attraction-products/changelog.md

# Actor input Schema

## `attractions` (type: `array`):

Trip.com attraction URLs such as https://www.trip.com/travel-guide/attraction/bangkok/the-grand-palace-77012, or bare attraction ids.

## `startUrls` (type: `array`):

Trip.com page addresses, with the option to load them in bulk from a file, a Google Sheet or a remote list. Use this when you have more links than you want to paste. Combined with anything in the list above.

## `maxProductsPerAttraction` (type: `integer`):

Stop after this many products for each attraction. 0 means every product on the shelf.

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

A run-wide ceiling across every target. The per-target limit above applies to each one separately, so ten targets at 50 each returns 500; set this to cap the total. Zero means no run-wide limit. Rows that report an input the actor could not resolve are not counted here and are never charged for.

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

Add the category, city and stock flags for each product, and its ticket terms: what is included and excluded, how to use it, and the booking and other notes. Costs two extra calls per product.

## `maxDetailProducts` (type: `integer`):

Cap how many products per attraction get the extra detail call.

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

ISO currency code. Prices come back quoted in it. Default USD.

## `locale` (type: `string`):

Locale the product names and tags come back in.

## `priceStoreName` (type: `string`):

Name a key-value store and each run remembers the last price per product, so rows carry the change since the previous run.

## `onlyNewOrChanged` (type: `boolean`):

Return only products whose price moved since the last run. Needs a price memory store.

## `includeRawData` (type: `boolean`):

Attach the unparsed product record to each row.

## `delayMs` (type: `integer`):

Pause between calls.

## `maxConcurrency` (type: `integer`):

How many requests run at once, each one paced by the delay above. The default is the fastest level measured clean; lower it only if a run reports refusals or errors.

## Actor input object example

```json
{
  "attractions": [
    "https://www.trip.com/travel-guide/attraction/bangkok/the-grand-palace-77012"
  ],
  "startUrls": [],
  "maxProductsPerAttraction": 0,
  "maxItems": 0,
  "includeDetails": false,
  "maxDetailProducts": 20,
  "currency": "USD",
  "locale": "en-XX",
  "priceStoreName": "",
  "onlyNewOrChanged": false,
  "includeRawData": false,
  "delayMs": 700,
  "maxConcurrency": 8
}
```

# Actor output Schema

## `dataset` (type: `string`):

Trip.com attraction products: every row the run returned.

## `stats` (type: `string`):

Counts for the run: what was resolved, fetched, filtered and returned.

# 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 = {
    "attractions": [
        "https://www.trip.com/travel-guide/attraction/bangkok/the-grand-palace-77012"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/tripcom-attraction-products").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 = { "attractions": ["https://www.trip.com/travel-guide/attraction/bangkok/the-grand-palace-77012"] }

# Run the Actor and wait for it to finish
run = client.actor("boncross/tripcom-attraction-products").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 '{
  "attractions": [
    "https://www.trip.com/travel-guide/attraction/bangkok/the-grand-palace-77012"
  ]
}' |
apify call boncross/tripcom-attraction-products --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,boncross/tripcom-attraction-products"
        }
    }
}
```

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/e2M1OF0qTHU5nXUof/builds/rdhzzpiegNq4Cstvw/openapi.json
