# Trip.com Attraction Availability & Prices (`boncross/tripcom-availability`) Actor

Scrape Trip.com attraction availability and prices. Just add product ids or product URLs and get every bookable date and package with the price, minimum price, remaining stock, sold-out flag and the options that define each package. It covers attractions, not hotels. $0.50 per 1,000 slots.

- **URL**: https://apify.com/boncross/tripcom-availability.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 $0.35 / 1,000 slot-listeds

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 Availability & Prices

### What is Trip.com Attraction Availability & Prices?

Trip.com Attraction Availability & Prices returns the booking calendar of a Trip.com tour or ticket: each date on sale, each package, what it costs that day and how many places are left. You paste a product id or a product link, and the calendar arrives as rows you can sort and chart.

You can point it at attraction tickets, day tours, transfers and rail or metro passes. Trip.com hotels are a separate family of actors, and if you only have an attraction page and not a product, [Trip.com Attraction Products Scraper](https://apify.com/boncross/tripcom-attraction-products) lists the products to feed in here.

Why use this one:

- You get stock, not just a price. All 390 slots in our 7 October 2026 sample came with the number of places left.
- A package is never averaged away. A shared tour and a private tour of the same product are separate rows with separate prices.
- The booking terms come with the price: ticket type, the most you can book at once, and the last day and time to book. Measured over 17 products of 17 kinds and 10 attraction tickets, those four were on every row.
- It's fast enough for a whole catalogue. 155 products returned 61,818 slots in 48 seconds.
- $0.50 per 1,000 slots on the Free plan, $0.35 on Business, with nothing to set up.

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

- 28 of 28 live checks on its inputs and filters passed on 7 October 2026
- 14 products run the same day across 9 destinations: 390 slots, 1 error row
- Charges matched the rows: 13 products, 390 slots, 1 checked
- A product id with no dates on sale gets a row saying so

What else you can do with it:

- Read the price before a sale next to the sale price, on the dates Trip.com has discounted
- See the options that define a package, such as event time, language, vehicle or meal type
- Trim the calendar to a date range, in any currency Trip.com quotes
- Keep a price memory between runs and get only the slots whose price moved
- Find out why a product has no calendar from a row that says so
- Download the lot as JSON, CSV, Excel, XML or HTML

People run it to watch a tour sell down date by date, to get an alert when a sold-out date reopens, to check that a reseller is honouring an agreed price, and to feed real bookable inventory into a price comparison. Remaining places per date is also a more direct measure of demand than a review count.

### What data is on each row?

| | |
|---|---|
| 📅 Date | ⏰ Session time, on timed products |
| 💵 Price for that date and package | Lowest price on the date |
| 🏷️ Price before a sale | 💱 Currency |
| 📦 Places remaining | Trip.com's wording for it ("Only 1 spot left") |
| 🎟️ Package id and name | Package options as name and value |
| ✅ Bookable flag | 🚫 Sold-out flag |
| 🧑 Ticket type, e.g. Adult, Child | 👥 Minimum party size |
| Maximum quantity per booking | ⏳ Booking cut-off: days ahead and time |
| 📝 Package description: validity, how to use | Resource id |
| 🆔 Product id | 🔗 Product link |
| 📈 Price change since last run | Previous price and when it was read |

### How to scrape Trip.com attraction availability

You don't need to write any code. It's a form, and the result opens as a table.

1. [Create a free Apify account](https://console.apify.com/sign-up) and open [Trip.com Attraction Availability & Prices](https://apify.com/boncross/tripcom-availability).
2. Open the tour or ticket on Trip.com and copy its address, or just the product id in it. Paste one or more into Products.
3. Pick a currency. Add a date range if you only care about part of the calendar.
4. Press Start, then download the slots as Excel, CSV or JSON.

### ⬇️ Input

Paste product ids or product links. A product is the ticket or tour you book, not the attraction's page. If you paste the whole link, the id is picked out of it.

Got a long list? Put the links in Start URLs, which can load them from a file, a Google Sheet or a remote list. Both inputs are used together.

You have two limits. "Maximum slots per product" applies to each product separately: ten products at 50 each returns 500. "Maximum results for the whole run" caps the total, and nothing past it is fetched or charged for. Both default to 0, which means no limit.

#### Two tours, every date on sale

```json
{
  "products": ["49278954", "89137206"],
  "currency": "USD"
}
```

The first is a floating market and railway market tour, the second a shared group tour with an 8:00 start. Both were in our 7 October 2026 sample.

#### One month of dates from a pasted link

```json
{
  "products": ["https://www.trip.com/things-to-do/detail/49278954"],
  "dateFrom": "2026-11-01",
  "dateTo": "2026-11-30",
  "currency": "USD"
}
```

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

```json
{
  "products": ["49278954", "89137206"],
  "priceStoreName": "tripcom-prices",
  "onlyNewOrChanged": true,
  "currency": "USD"
}
```

#### Package names in Japanese, priced in yen

```json
{
  "products": ["49278954"],
  "locale": "ja-JP",
  "currency": "JPY"
}
```

| Field | Notes |
|---|---|
| `products` | Product ids, or any Trip.com link that contains one. |
| `startUrls` | The same links, loaded in bulk. |
| `maxSlotsPerProduct`, `maxItems` | The per-product cap and the run-wide cap. Both default to `0`, no limit. |
| `dateFrom`, `dateTo` | Keep only dates in this range, as YYYY-MM-DD. Empty keeps the whole calendar. |
| `currency` | ISO code, default `USD`. |
| `locale` | Language of package and option names, default `en-XX`. |
| `priceStoreName`, `onlyNewOrChanged` | The price memory, and the switch that returns only slots whose price moved. |
| `includeRawData` | Adds Trip.com's untouched per-package record to each row. Default `false`. |
| `delayMs`, `maxConcurrency` | Pacing. Defaults `800` and `8`. |
| `poiId`, `scenicSpotId` | Attraction id overrides, rarely needed. |

#### For developers

- Trip.com checks a product against the attraction it belongs to. The actor looks that attraction up for you. To pin it yourself, add the attraction id after an @ sign, as in `59489114@10558849`, or set `poiId` (Attraction id override), which applies to any product that doesn't have one of its own. `scenicSpotId` is an alternative identifier for when you don't have the attraction id.
- `dateFrom` and `dateTo` trim the calendar Trip.com returns. They can't extend it.
- `maxItems` doesn't count the row for a product that couldn't be read or has no dates. The first is free, and the second costs the `product-checked` fee.
- `priceStoreName` names a key-value store that remembers the last price per package and date. Rows then have `previousPrice`, `previousScrapedAt`, `priceChange` and `priceChangePct`. `onlyNewOrChanged` needs that store.
- `delayMs` (default 800, up to 10,000) is the pause between products. `maxConcurrency` (default 8, from 1 to 8) is how many requests run at once. The default is the fastest level we measured clean, and the only reason to lower it is a run that reports refusals or errors.
- Rows are saved as they arrive. If Apify restarts a run part-way through, it continues from where it stopped, and no slot is saved or charged twice.

### ⬆️ Output

You get one row per date and package, in the dataset and as a table in the Output tab. This one is from a run on 7 October 2026:

```json
{
  "input": "49278954",
  "id": "49278954-103591277-2026-10-09-all-103591278",
  "url": "https://www.trip.com/things-to-do/detail/?productId=49278954",
  "productId": "49278954",
  "date": "2026-10-09",
  "dateMinPrice": 19.72,
  "packageId": "103591277",
  "packageName": "A · car (type to be confirmed) · D-meeting point pick-up and drop-off | Damnoen Saduak + Maeklong | English-English",
  "salesProperties": {
    "Itinerary": "A",
    "Brand car series": "car (type to be confirmed)",
    "Package": "D-meeting point pick-up and drop-off | Damnoen Saduak + Maeklong | English-English"
  },
  "resourceId": "103591278",
  "ticketType": "Adult",
  "timeSlot": null,
  "price": 19.72,
  "priceText": "19.72",
  "priceListed": 21.92,
  "minPrice": 19.72,
  "stock": 13,
  "stockText": null,
  "minQuantity": 1,
  "maxQuantity": 12,
  "bookingCutoffDays": 1,
  "bookingCutoffTime": "23:00",
  "packageDescription": null,
  "isSoldOut": false,
  "isAvailable": true,
  "currency": "USD",
  "previousPrice": null,
  "previousScrapedAt": null,
  "priceChange": null,
  "priceChangePct": null,
  "scrapedAt": "2026-10-07T17:01:42.995Z"
}
```

A few columns need a word:

| Column | Meaning |
|---|---|
| `id` | Product, package, date, time slot and resource joined together. One row is one bookable slot. |
| `dateMinPrice` | The lowest package price on that date, after any sale. |
| `priceListed` | The price before a sale. Filled only on dates and packages Trip.com has on sale, otherwise null. |
| `timeSlot` | The session time on timed products ("11:00"). Null where the product is sold by the day, as above. |
| `stock`, `stockText` | Places left as a number, and Trip.com's wording where it shows one. |
| `bookingCutoffDays`, `bookingCutoffTime` | The last moment to book: at least that many days before the date, by that time. |
| `maxQuantity` | The most that can be booked at once for that date. |
| `packageDescription` | Validity and how-to-use text. Tours, transfers and passes may have it. Attraction tickets don't. |

In the 7 October 2026 sample of 390 slots, `timeSlot` was filled on 30 and `stockText` on 45. Those depend on how the product is sold. Price, date and `stock` were on all 390.

A product that can't be read still gets a row: the input, the product id and an `error` telling you what happened and what to try next. That row isn't charged. A product id Trip.com answers with no packages or dates gets the same kind of row, for the $0.0005 `product-checked` fee.

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

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, per run | $0.002 | $0.002 | $0.002 | $0.002 |
| `product-resolved`, per product | $0.002 | $0.002 | $0.002 | $0.002 |
| `product-checked`, per product Trip.com answered with no dates, instead of `product-resolved` | $0.0005 | $0.0005 | $0.0005 | $0.0005 |
| `slot-listed`, per row returned | $0.0005 | $0.00045 | $0.0004 | $0.00035 |

Enterprise plans pay the Business price.

**$0.50 per 1,000 slots** on the Free plan, $0.35 on Business. That's the whole price: there's no proxy to set up, and platform usage is included.

Rows removed by your date range, and unchanged rows when you ask for only new or changed, are free. A product with no calendar costs only the $0.0005 `product-checked` fee. A product that couldn't be read is free.

- Two products returning 220 rows: $0.002 + 2 × $0.002 + 220 × $0.0005 = **$0.116** ($0.083 on Business).
- A daily watch on one product returning 110 changed rows: $0.002 + $0.002 + 110 × $0.0005 = **$0.059** ($0.0425 on Business).

The $5 of credits in Apify's Free plan each month buys about 43 runs the size of the first example, or about 9,400 slots.

One thing to plan for: a slot is a row, and some products have a lot of them. Across the 155 products in the speed table below, the average was about 400 slots each, and a pass with many packages over a long calendar returns far more. Set "Maximum slots per product" or a date range if you're testing.

### How big is a calendar, and how fast is a run?

Whole runs on Apify, start-up included, three runs each on 2 October 2026:

| Run | Rows | Time | Cost at the Free-plan price |
|---|---|---|---|
| One product, first 8 slots | 8 | 5.8 to 6.7 s | $0.008 |
| Four products (one with no calendar), every slot | 446 + 1 notice | 4.4 to 4.7 s | $0.2315 |
| 155 products, every slot | 61,818 + 7 notices | 48 s | $31.2105 |

A large run delivers about 75,000 slots a minute, at about 400 slots per product. An hour covers roughly 10,000 products.

How far ahead you can see is Trip.com's decision. Two products measured on 11 September 2026 returned 28 and 39 dates, over 23 packages and 220 rows between them.

### Watch prices on a schedule, or call it from code

A price watch is what this data is for. Create an Apify Schedule, name a price memory store, switch on "Only new or changed", and each run hands you just the slots that moved. Send them to Slack or a Google Sheet through Apify's integrations, or fire a webhook when the run ends.

From code, `POST https://api.apify.com/v2/acts/boncross~tripcom-availability/run-sync-get-dataset-items` with the input as the body returns the slots in one request. The `apify-client` packages on npm and PyPI cover longer runs. AI agents reach it through the Apify MCP server at `mcp.apify.com`, where it's the tool `boncross/tripcom-availability`: give it product ids and it reads the calendar back.

### Limitations: what the calendar won't tell you

- You won't find the product name on a row. The calendar doesn't include it, and rows identify the product by its id and link. [Trip.com Product Details Scraper](https://apify.com/boncross/tripcom-product-details) has the name and description.
- You get only the dates Trip.com publishes. A range wider than the calendar adds nothing.
- On a pass that books several attractions at once, `timeSlot` is the first attraction's session and `salesProperties` has all of them.
- A few sellers name their ticket types in Chinese only. The common ones are given in English ("Adult", "Standard price", "Group(1-4 People)"). A name we haven't seen is shown as the seller wrote it.
- An id Trip.com doesn't know looks the same to us as a product with no calendar. It gets the same row and the same $0.0005 fee.

### FAQ

#### What exactly do I paste?

Open the tour or ticket on Trip.com and look at the address. The id is the number after `/detail/` or after `productId=`. You can paste the whole address and skip the copying.

#### I only have the attraction's page. What now?

Run [Trip.com Attraction Products Scraper](https://apify.com/boncross/tripcom-attraction-products) on it first. It lists the tickets and tours sold for that attraction, each with the product id this actor takes. To find products by keyword or city, use [Trip.com Things to Do Search](https://apify.com/boncross/tripcom-product-search).

#### Why did a product return no slots?

There are three usual reasons. Some products are sold without a date, such as a meal voucher or a ticket valid for 90 days, and have no calendar. A product answers only in the languages of the markets where Trip.com sells it, so one that isn't on the Japanese site returns nothing for `ja-JP` while it answers in English. And if the attraction lookup fails, a product comes back as a row reporting no dates: add its attraction id after an @ sign and run it again. In each case you get a row saying what happened.

#### Why does a date disappear between runs?

Trip.com removes a date from the calendar once it sells out or leaves the sale window. It doesn't show it with zero places. A date that vanished is a signal, and a date that returns is a reopening.

#### Why do two rows share a date?

A product usually sells several packages: a shared tour and a private one, a lunch sitting and a dinner sitting. Each has its own row, price and remaining places.

#### Is the price per person?

It's per package for the date. Tours, transfers and passes name who the price is for in `ticketType` (Adult, Child, Number of people). Attraction tickets don't, and give you only the minimum party size.

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

Neither. There's nothing to configure, no login, and no proxy charge on top of the price per slot.

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

The actor reads only what Trip.com shows any visitor who isn't logged in: public prices and availability. Scraping public data is generally lawful, but how you use it is your responsibility, including Trip.com's terms and the law where you operate.

### More from BonCross

- [Trip.com Attraction Products Scraper](https://apify.com/boncross/tripcom-attraction-products): Every product Trip.com sells for an attraction.
- [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

Seen a price or a stock figure that doesn't match what Trip.com shows for that date? Tell us on the Issues tab in Apify Console, with the product id and the date. BonCross reads every report and replies there.

# Changelog

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

# Actor input Schema

## `products` (type: `array`):

Trip.com attraction product ids, or any Trip.com URL that contains productId. Each product's attraction is looked up automatically; to pin it yourself, add the attraction id after an @ sign, for example 59489114@10558849.

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

## `maxSlotsPerProduct` (type: `integer`):

Stop after this many slots for each product. Zero returns every slot Trip.com publishes, which for a product with many packages and dates can be a few hundred rows.

## `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 a product that could not be read are not counted here and are not charged for. A product Trip.com answers with no dates is not counted either, and costs only the small product-checked fee.

## `dateFrom` (type: `string`):

Earliest date to keep, as YYYY-MM-DD. Leave empty to keep every date the calendar offers.

## `dateTo` (type: `string`):

Latest date to keep, as YYYY-MM-DD. Leave empty to keep every date the calendar offers.

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

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

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

Trip.com locale for package and option names, such as en-XX, en-US, ja-JP, ko-KR or zh-HK. A product answers only in the languages of the markets where Trip.com sells it: one not sold on the Japanese site returns no slots for ja-JP.

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

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

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

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

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

Add the untouched per-package record from Trip.com to every row.

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

Pause between products.

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

## `poiId` (type: `integer`):

Advanced. Attraction id applied to every product that does not carry its own. The number at the end of the attraction page address.

## `scenicSpotId` (type: `integer`):

Advanced. Alternative attraction identifier, used when an attraction id is not to hand.

## Actor input object example

```json
{
  "products": [
    "49278954",
    "89137206"
  ],
  "startUrls": [],
  "maxSlotsPerProduct": 0,
  "maxItems": 0,
  "dateFrom": "",
  "dateTo": "",
  "currency": "USD",
  "locale": "en-XX",
  "priceStoreName": "",
  "onlyNewOrChanged": false,
  "includeRawData": false,
  "delayMs": 800,
  "maxConcurrency": 8
}
```

# Actor output Schema

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

Trip.com availability: 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 = {
    "products": [
        "49278954",
        "89137206"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/tripcom-availability").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 = { "products": [
        "49278954",
        "89137206",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("boncross/tripcom-availability").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 '{
  "products": [
    "49278954",
    "89137206"
  ]
}' |
apify call boncross/tripcom-availability --silent --output-dataset

```

## MCP server setup

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

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/dFbBDbiJuHS9gNNC3/builds/8se23SHHdunFc9U1l/openapi.json
