# Klook Activity Reviews Scraper (`boncross/klook-reviews`) Actor

Scrape every review Klook shows for an activity. Just add activity ids or URLs and get the rating, full text, English translation, photos, reviewer, date, likes and the package booked, plus the activity rating and AI summary. Sort them or get only new ones. $2.00 per 1,000 reviews.

- **URL**: https://apify.com/boncross/klook-reviews.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 $1.40 / 1,000 review-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

## Klook Activity Reviews Scraper

### What is Klook Activity Reviews Scraper?

Klook Activity Reviews Scraper collects the traveller reviews of any Klook tour, ticket or pass. You paste the activity's link and get each review with its rating, its full text, Klook's English translation and the exact package the reviewer booked.

That last part is what most review data is missing. A Bangkok temple tour on Klook sells 20 packages, private and join-in, half-day and full-day. A complaint about "the tour" is only useful once you know which one, and each row here names the package and its id.

- Reviews written in Chinese, Korean, Thai or Japanese arrive with Klook's translation beside the original. In a sample of 25 recent reviews of Seoul's WOWPASS card, 23 had one.
- It's quick: the newest 100 reviews of each of 15 activities, 1,500 in all, took 5 to 7 seconds.
- Run it on a schedule and you get only the reviews posted since last time. Reviews you've already had are free.
- $2.00 per 1,000 reviews on the Free plan, $1.40 on Business, with no proxy to arrange and no usage charges on top.

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

- 26 of 26 live checks on its inputs and filters passed on 8 October 2026
- 14 activities run on 7 October 2026: 257 reviews, 5 summaries, 2 error rows
- Charges matched the rows: 12 activities, 257 reviews
- An unknown id or an activity with no reviews gets an uncharged row saying so

Reviews are one of four things you can get from Klook with BonCross actors. To find activities in a city, use [Klook Search Scraper](https://apify.com/boncross/klook-search). For an activity's packages, description and FAQs there's [Klook Activity Details Scraper](https://apify.com/boncross/klook-activity-details), and for dated prices and places left, [Klook Activity Availability & Prices](https://apify.com/boncross/klook-availability).

### How to scrape Klook reviews

1. [Sign up for a free Apify account](https://console.apify.com/sign-up), then open [Klook Activity Reviews Scraper](https://apify.com/boncross/klook-reviews).
2. Paste one or more Klook activity links. The activity number on its own works too.
3. Choose how many reviews you want per activity and the order: newest, most relevant, highest or lowest rated.
4. Press Start. A couple of hundred reviews take a few seconds.
5. Open the Output tab and download the reviews as Excel, CSV or JSON.

### What data comes with each review?

| | |
|---|---|
| ⭐ Rating out of five | Rating wording, such as Fantastic |
| 📝 Full review text | 🌐 Klook's English translation |
| 🎟️ Package booked, name and id | 🔗 Activity link |
| 👤 Reviewer name and avatar | 📅 Posted date and time |
| 📷 Review photos, full size | Photo count |
| 👍 Helpful votes | Whether the operator replied |
| Activity rating and review count | Klook's own review summary |
| Review id | The sort and filter you used |

### ⬇️ Input

All the form needs is an activity link. Left alone, it returns the newest 200 reviews of each activity plus one row with Klook's own summary of what reviewers say.

You have two limits. "Max reviews per activity" applies to each activity separately: ten activities at 50 each returns 500. Set it to 0 to keep going until the reviews run out. "Maximum results for the whole run" caps the total, and nothing past it is fetched or charged.

#### The newest 200 reviews of one activity

```json
{
  "activities": ["https://www.klook.com/en-GB/activity/3021-bangkok-must-visit-landmarks-day-tour/"],
  "maxReviewsPerActivity": 200,
  "sort": "newest"
}
```

#### Everything written since a date

```json
{
  "activities": ["1163"],
  "sort": "newest",
  "reviewedAfter": "2026-08-01",
  "maxReviewsPerActivity": 1000
}
```

#### The worst reviews first, for a quality check

```json
{
  "activities": ["122675"],
  "sort": "lowest",
  "maxReviewsPerActivity": 500
}
```

#### Only reviews with photos

```json
{
  "activities": ["3021"],
  "filter": "photos",
  "onlyWithPhotos": true,
  "maxReviewsPerActivity": 300
}
```

#### A daily watch on two activities, new reviews only

```json
{
  "activities": ["3021", "86208"],
  "sort": "newest",
  "maxReviewsPerActivity": 100,
  "dedupStoreName": "klook-reviews-seen"
}
```

| Field | Notes |
|---|---|
| `activities` | Klook activity links or activity numbers. |
| `startUrls` | The same links loaded in bulk from a file, a Google Sheet or a remote list. Combined with `activities`. |
| `maxReviewsPerActivity`, `maxItems` | The per-activity limit (default 200) and the run-wide one (default 0, no limit). |
| `sort` | `newest` (default), `relevant`, `highest` or `lowest`. |
| `filter` | `all` (default), `photos`, or `mylanguage` for reviews written in your language. |
| `minRating` | Drops reviews below this score out of 5. Default 0. Filtered rows are free. |
| `reviewedAfter` | A date as YYYY-MM-DD. Older reviews are left out. |
| `onlyWithPhotos` | Drops reviews with no images. Default off. |
| `includeAiSummary` | Adds the summary row per activity. Default on. |
| `currency`, `language` | Default `USD` and `en_GB`. The language also sets the language of the translation and the summary. |
| `dedupStoreName` | Names the store that remembers which reviews you've had. |
| `pageSize`, `maxConcurrency`, `delayMs` | Advanced. See below. |

#### For developers

- When a filter or the only-new store keeps nothing, the read stops early: after 5 pages in a row with no review kept, or after about three times the pages the per-activity limit needs.
- On the newest-first order it also stops at the `reviewedAfter` date and at the first review an earlier run returned. That's why a scheduled run with `dedupStoreName` returns only the reviews posted since the last run. Older reviews that an earlier run didn't return aren't filled in later.
- On the other orders `reviewedAfter` works as a filter, because those lists aren't in date order.
- `pageSize` (default 50, from 10 to 50) is how many reviews are asked for at a time. A thousand reviews is twenty requests.
- Klook occasionally returns an empty page part way down. The actor retries, and stops only when two pages in a row are empty.
- `maxConcurrency` (default 64, from 1 to 64) is how many requests run at once, and `delayMs` (default 0, up to 10,000) adds a pause before each. We'd leave both alone unless a run reports errors.
- `activity-resolved` is charged once Klook returns a rating or a review for the activity. An id with neither gets a row with an `error` and no fee.
- If a review page can't be read after the activity resolved, the reviews already read are kept and one free row names the page where the list stopped.
- If Apify moves a run to another server part-way through, it carries on where it stopped. Rows already delivered aren't written or charged again.

### ⬆️ Output

Each review is one row. This one is from the Bangkok temple tour, written in Chinese by someone on the join-in full-day package:

```json
{
  "input": "https://www.klook.com/en-US/activity/3021-bangkok-must-visit-landmarks-day-tour/",
  "dataType": "review",
  "id": "19478229",
  "reviewId": "19478229",
  "url": "https://www.klook.com/en-GB/activity/3021-activity/",
  "activityId": "3021",
  "rating": 5,
  "ratingScale": 5,
  "ratingText": "Fantastic",
  "text": "体验很好，中英文导游都有，会有讲解，行程安排也比较合理，非常适合第一次来泰国参观的游客。导游CHOPIN和她的搭档，另一个会说中文的姐姐，比较负责幽默。",
  "textTranslated": "Great experience, with both Chinese and English-speaking guides providing explanations. The itinerary is quite well-arranged, making it very suitable for first-time visitors to Thailand. The tour guide CHOPIN and her partner, another friendly lady who speaks Chinese, were very responsible and humorous.",
  "isTranslated": true,
  "authorName": "Klook客路用户",
  "authorAvatar": "https://cdn.klook.com/upload/img200X200/Property_1_zh_CN_03.png",
  "postedAt": "2026-10-05T10:20:39.000Z",
  "postedText": "2026-10-05T10:20:39.000Z",
  "packageId": "608302",
  "packageName": "Join-in · Emerald Buddha + Grand Palace + Wat Arun + Wat Pho · Full day · With admission tickets · Siam Paragon Meet Up",
  "images": [
    "https://cdn.klook.cn/user_review/product/1949762/fbd670a4-bbd5-42d8-6450-39f17955d7e4.0*1200.jpeg",
    "https://cdn.klook.cn/user_review/product/1949762/40ea4079-54ba-4011-7be4-3037dbe77cd7.0*1200.jpeg",
    "https://cdn.klook.cn/user_review/product/1949762/d96a9030-f396-44a0-5190-f1f9a57634f0.0*1200.jpeg"
  ],
  "imageCount": 3,
  "likes": 1,
  "hasReply": false,
  "activityRating": 4.8,
  "activityRatingScale": 5,
  "activityReviewCount": 5787,
  "sort": "newest",
  "filter": "all",
  "currency": "USD",
  "scrapedAt": "2026-10-07T16:50:02.251Z"
}
```

With the summary switched on, each activity that has one also produces a row with `dataType: "summary"`. It holds the activity rating, its wording, the review count and Klook's summary points in `aiSummary`, each with a title and text, under the heading Klook gives them in `aiSummaryTitle`. For this tour the points were Overall impression, Guide, Itinerary, Quality of transfer and Value for money. The summary row isn't charged as a review.

`postedText` keeps the date as Klook wrote it, beside the parsed `postedAt`. A row with an `error` and no review fields usually means Klook has no reviews and no rating for that id. The `error` text says which case you're looking at.

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

| Run | Rows | Time | Price |
|---|---|---|---|
| Newest 200 reviews of one activity with 89,507 reviews | 200 reviews + 1 summary | 2 to 7 s | $0.404 |
| Newest 200 reviews each of three activities | 600 reviews + 2 summaries | 1.5 to 4 s | $1.208 |
| Newest 100 reviews each of 15 activities | 1,500 reviews + 7 summaries | 5 to 7 s | $3.032 |

Times are whole runs, start to finish. At roughly 15,000 reviews a minute, what limits you is how deep each activity's reviews go, not the clock.

On depth, be realistic. Very deep paging thins out well before the headline review count, so treat that count as the size of the pool. It isn't a promise that each one can be reached.

### How much does it cost to scrape Klook reviews?

| Event | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| `actor-start`, per run | $0.002 | $0.002 | $0.002 | $0.002 |
| `activity-resolved`, per activity | $0.002 | $0.002 | $0.002 | $0.002 |
| `review-scraped`, per review returned | $0.002 | $0.0018 | $0.0016 | $0.0014 |

Enterprise plans pay the Business price.

**$2.00 per 1,000 reviews** on the Free plan, $1.40 on Business, platform usage and proxy included. You don't pay for reviews a filter removed, for reviews an earlier run already gave you, or for the summary row.

- 200 reviews of one activity: $0.002 + $0.002 + 200 × $0.002 = **$0.404** ($0.284 on Business).
- A daily watch on five activities that finds 40 new reviews between them: $0.002 + 5 × $0.002 + 40 × $0.002 = **$0.092** ($0.068 on Business).

On Apify's Free plan, the $5 of monthly credits pays for about 2,400 reviews at the size of the first example, or 54 days of that daily watch.

### Monitoring, analysis and your own code

The setup we'd recommend for anyone managing a product on Klook is the daily watch: an Apify Schedule, the newest-first order and an only-new store. Each morning you get yesterday's reviews, and a webhook can post to Slack when a run brings any back.

People also use the reviews to find out which package draws the complaints, to compare how one attraction is reviewed across operators, to pull quotes and photos for a travel guide, and to build a translated corpus for sentiment analysis.

From code, `POST https://api.apify.com/v2/acts/boncross~klook-reviews/run-sync-get-dataset-items` with the input as the JSON body returns the reviews in one request. Through the Apify MCP server (`mcp.apify.com`) an AI agent sees the actor as the tool `boncross/klook-reviews` and can be asked to summarise the last month of reviews for an activity.

### Limitations

- Klook reviews have no headline, and there's no title field. The rating wording, such as Fantastic, is the closest thing.
- Klook masks part of each reviewer's name. The full name can't be recovered.
- The language a review was written in isn't published, and rows have no language field. The translation follows your language setting.
- Operator replies are flagged with `hasReply`. The reply text isn't returned.
- The photo filter narrows the pool without reordering it. On a heavily reviewed activity the first page can look unchanged.
- "Most relevant" is Klook's own ranking. Nothing on the row lets you check it, unlike the newest and rating orders.
- Activities only. Klook's hotel pages use different addresses and ids, and this actor doesn't read them.

### FAQ

#### Do I need proxies or a Klook account?

You need neither, and there's no proxy charge added to the per-review price.

#### Where do I find the activity number?

It's the number in the address of the activity page: 3021 in `klook.com/en-GB/activity/3021-bangkok-must-visit-landmarks-day-tour/`. Paste the whole address and the number is picked out for you.

#### How do I get only the bad reviews?

Sort by lowest rating and stop at the number you need. The "Minimum rating" filter works the other way round: it keeps the good ones.

#### How do I get only the reviews posted since my last run?

Give "Only-new store" a name, keep the newest-first order, and use the same name on each run. The run stops at the first review it has returned before.

#### Why did I get fewer reviews than the activity's review count?

Klook's list thins out at depth, well before the headline count. An activity showing 89,507 reviews won't hand over all of them. Filters reduce the number as well, and filtered rows cost nothing.

#### What happens with an activity that has no reviews, or a wrong id?

Klook answers both the same way, with no reviews and no rating. You get one row for that input saying so, and no activity fee is charged. The same goes for an activity Klook wouldn't answer for at all on this run: one free row that says what happened and what to try next.

#### Can I get the reviews in English?

Reviews written in other languages come with Klook's translation in `textTranslated`, next to the original in `text`. Set "Language" to another locale and the translation and the summary follow it.

#### Is it legal to scrape Klook reviews?

The actor reads reviews Klook shows to any visitor who isn't logged in. Reviewer names arrive already masked by Klook. Scraping public data is generally lawful, but reviews are personal opinions written by people, so check Klook's terms and the data protection law that applies to you before you republish them.

### More from BonCross

- [Klook Activity Details Scraper](https://apify.com/boncross/klook-activity-details): Full Klook activity records.
- [Klook Activity Availability & Prices](https://apify.com/boncross/klook-availability): Klook availability and prices.
- [Trip.com Attraction Reviews Scraper](https://apify.com/boncross/tripcom-reviews): Trip.com reviews for any attraction.
- [KKday Product Availability & Prices](https://apify.com/boncross/kkday-availability): KKday availability and prices for any product.
- [Trip.com Hotel Search Scraper](https://apify.com/boncross/tripcom-hotel-search): Every hotel Trip.com lists for a destination and your dates.
- [Accor Hotel Details Scraper](https://apify.com/boncross/accor-hotel-details): Full Accor hotel records.

### Your feedback

If a review on Klook's page is missing from your rows, or a translation looks cut short, open an issue on the Issues tab in Apify Console and include the activity link. We read each one and reply there.

# Changelog

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

# Actor input Schema

## `activities` (type: `array`):

Klook activity URLs, or activity ids. The activity number is the one in the address, such as 3021 for the Bangkok temple tour.

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

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

## `maxReviewsPerActivity` (type: `integer`):

Stop after this many reviews for each activity. 0 means keep going until the feed runs out.

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

## `sort` (type: `string`):

Order the reviews come back in.

## `filter` (type: `string`):

Narrow the feed to reviews with photos, or to reviews written in your language.

## `minRating` (type: `integer`):

Drop reviews below this score out of 5. 0 keeps everything. Filtered rows are free.

## `reviewedAfter` (type: `string`):

Stop once reviews are older than this date, written as YYYY-MM-DD. Works best with the newest-first sort, where the actor can stop as soon as it passes the date.

## `onlyWithPhotos` (type: `boolean`):

Drop reviews that carry no images. Filtered rows are free.

## `includeAiSummary` (type: `boolean`):

Add one extra row per activity carrying Klook's own summary of what reviewers say.

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

ISO currency code used for any prices in the response. Default USD.

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

Klook locale code, such as en_GB, en_US or ja_JP. Sets the language of the translation and the summary.

## `dedupStoreName` (type: `string`):

Name a key-value store and the actor remembers which reviews it has already returned, so a scheduled run brings back only new ones.

## `pageSize` (type: `integer`):

How many reviews to ask for at a time. Larger pages mean fewer requests.

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

How many requests run at once across the whole run. The default is the fastest level measured clean; lower it only if a run reports refusals or errors.

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

Optional pause before each call, in milliseconds. 0 (the default) runs as fast as the parallel limit allows.

## Actor input object example

```json
{
  "activities": [
    "https://www.klook.com/en-GB/activity/3021-bangkok-must-visit-landmarks-day-tour/"
  ],
  "startUrls": [],
  "maxReviewsPerActivity": 200,
  "maxItems": 0,
  "sort": "newest",
  "filter": "all",
  "minRating": 0,
  "onlyWithPhotos": false,
  "includeAiSummary": true,
  "currency": "USD",
  "language": "en_GB",
  "dedupStoreName": "",
  "pageSize": 50,
  "maxConcurrency": 64,
  "delayMs": 0
}
```

# Actor output Schema

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

Klook reviews: 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 = {
    "activities": [
        "https://www.klook.com/en-GB/activity/3021-bangkok-must-visit-landmarks-day-tour/"
    ],
    "reviewedAfter": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("boncross/klook-reviews").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 = {
    "activities": ["https://www.klook.com/en-GB/activity/3021-bangkok-must-visit-landmarks-day-tour/"],
    "reviewedAfter": "",
}

# Run the Actor and wait for it to finish
run = client.actor("boncross/klook-reviews").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 '{
  "activities": [
    "https://www.klook.com/en-GB/activity/3021-bangkok-must-visit-landmarks-day-tour/"
  ],
  "reviewedAfter": ""
}' |
apify call boncross/klook-reviews --silent --output-dataset

```

## MCP server setup

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

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/wBIwhXvDCV8kulKFf/builds/5O7Ky0j8txPeEMa7w/openapi.json
