# Tokopedia Shop Reviews Scraper (`auliax20/tokopedia-reviews`) Actor

Crawls every product of a Tokopedia shop and collects all of its reviews.

- **URL**: https://apify.com/auliax20/tokopedia-reviews.md
- **Developed by:** [Aulia Ulkhairi](https://apify.com/auliax20) (community)
- **Categories:** Developer tools, Automation, E-commerce
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / actor start

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## Tokopedia Shop Reviews Scraper

Give it one or more **Tokopedia shop URLs** and it crawls **every product** of each
shop and collects **all of their reviews** — text, star rating, reviewer, date,
photos, videos, and seller replies — as clean, structured JSON ready for
spreadsheets, BI tools, or sentiment analysis.

Perfect for **brand monitoring, competitor research, product feedback analysis, and
review datasets**.

### Features

- 🏬 **Whole-shop crawl** — point it at a shop, get reviews for every product.
- ⭐ **Full review detail** — rating, text, reviewer, timestamp, likes, variant,
  images, and videos.
- 💬 **Seller replies** — optionally captured as separate rows to measure brand
  responsiveness.
- 📊 **Per-product summaries** — average rating and 1–5 star distribution per product.
- 🗓️ **Date & rating filters** — only pull reviews since a date, or within a star range.
- 🔁 **Incremental mode** — remember what you've already scraped and only fetch new
  reviews on the next run (ideal for scheduled monitoring).
- 🧹 **Clean, stable schema** — every field documented; drop straight into your pipeline.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `shopUrls` | string\[] | — | Tokopedia shop URLs (`https://www.tokopedia.com/<slug>`). |
| `shopIds` | string\[] | — | Numeric shop ids — use if URL resolution fails. |
| `maxProductsPerShop` | int | `0` | Cap products per shop. `0` = all. |
| `maxReviewsPerProduct` | int | `0` | Cap reviews per product. `0` = all. |
| `onlyProductsWithReviews` | bool | `false` | Skip products the listing marks as 0 reviews (listing count is unreliable, so off by default). |
| `reviewSort` | enum | `Most helpful` | Most helpful / Newest / Oldest / Highest / Lowest. |
| `reviewsSince` | date | `""` | Keep only reviews on/after this date. Sorts newest-first and **stops** a product once older reviews are reached. |
| `includeProductSummaries` | bool | `true` | Emit one aggregate row per product to the `product-summaries` dataset. |
| `includeSellerReplies` | bool | `true` | Emit seller replies as extra rows (`source_label: Tokopedia Seller Reply`). |
| `dedup` | bool | `false` | Remember review ids across runs and skip seen ones. For scheduled monitoring. |
| `minRating` / `maxRating` | int | `0` | Keep only reviews within this 1–5 range. `0` = no filter. |
| `productConcurrency` | int | `3` | Products scraped in parallel. |
| `requestDelayMs` | int | `400` | Polite delay between requests. |
| `proxyConfiguration` | proxy | off | Apify Proxy settings. |

At least one of `shopUrls` / `shopIds` is required. When `reviewsSince` or `dedup`
is enabled, review sort is forced to newest-first so early-stop can work.

#### Example input

```json
{
  "shopUrls": ["https://www.tokopedia.com/wahanakaryastore"],
  "maxReviewsPerProduct": 200,
  "reviewsSince": "2026-01-01",
  "includeSellerReplies": true
}
```

### Output

One row per review (and per seller reply when enabled) in the default dataset:

```jsonc
{
  "external_id":  "tokopedia-review-1492210321",
  "author_handle":"L***i",
  "author_name":  "L***i",
  "body":         "Trimakasih paket nya udah sampai...",
  "posted_at":    "2025-05-29T17:07:08.000Z",
  "url":          "https://www.tokopedia.com/wahanakaryastore/solder-...",
  "source_label": "Tokopedia Review",
  "likes":        0,          // helpful/like count
  "comments":     0,          // 1 if the seller replied
  "reach":        0,          // reserved (always 0)
  "rating":       5,          // 1-5
  "raw": {
    "platform": "tokopedia",
    "feedbackId": "1492210321",
    "productId": "100230143849",
    "productName": "...",
    "variantName": "Solder 60w+Timah 5m",
    "shopId": "7494083584907249524",
    "shopName": "WahanaKaryaStore",
    "isAnonymous": true,
    "relativeTime": "Lebih dari 1 tahun lalu",
    "sellerReply": null,
    "images": ["https://..."],
    "videos": [],
    "badRatingReason": null
  }
}
```

Every field is documented in the actor's **output schema**, so the Output tab shows
a clean, labelled table you can export to JSON, CSV, Excel, or via API.

#### Extra datasets

- **`product-summaries`** (when `includeProductSummaries`) — one row per product:
  `totalReviewsReported`, `reviewsCollected`, `averageRatingCollected`,
  `ratingDistribution` (1–5 star counts), `partial` flag. The star distribution is
  computed from the reviews actually fetched, so it's exact only on a full pull
  (no `maxReviewsPerProduct` / `reviewsSince` / `dedup`).
- **`tokopedia-reviews-state`** key-value store (when `dedup`) — persists seen review
  ids across runs.

### Notes

> Tokopedia sits behind **Akamai Bot Manager**. Plain datacenter IPs may get
> challenged. If you see repeated failures, enable **Apify Proxy** (RESIDENTIAL,
> country `ID`) in the input.

The scraper reads Tokopedia's public GraphQL endpoints (no login required). If
Tokopedia changes its API and a run starts erroring, please report it — signatures
occasionally change and the queries need re-capturing.

### Run locally

```bash
npm install
## create storage/key_value_stores/default/INPUT.json with your input, then:
npm start
```

# Actor input Schema

## `shopUrls` (type: `array`):

Tokopedia shop URLs, e.g. https://www.tokopedia.com/wahanakaryastore . The actor resolves the numeric shop id automatically.

## `shopIds` (type: `array`):

Numeric Tokopedia shop ids. Use this if URL resolution fails (e.g. 7494083584907249524). Optional alternative/supplement to Shop URLs.

## `maxProductsPerShop` (type: `integer`):

Stop after this many products per shop. 0 = no limit (all products).

## `maxReviewsPerProduct` (type: `integer`):

Stop after this many reviews per product. 0 = no limit (all reviews).

## `onlyProductsWithReviews` (type: `boolean`):

If on, skip products whose listing reports reviewCount = 0. NOTE: Tokopedia's listing count is often unreliable, so this is OFF by default and every product is probed for reviews.

## `reviewSort` (type: `string`):

How Tokopedia sorts the reviews it returns. Ignored (forced to Newest) when 'reviewsSince' or 'dedup' is enabled, so early-stop can work.

## `reviewsSince` (type: `string`):

Only keep reviews posted on/after this date (ISO, e.g. 2026-05-01). Sorts newest-first and STOPS paginating a product once older reviews are reached. Empty = no date filter.

## `includeProductSummaries` (type: `boolean`):

Push one aggregate row per product (total reviews, average rating, 1-5 star distribution) to a separate 'product-summaries' dataset.

## `includeSellerReplies` (type: `boolean`):

When a review has a seller reply, push it as an additional mention (source\_label 'Tokopedia Seller Reply') linked to the original review.

## `dedup` (type: `boolean`):

Remember review ids across runs (in a named key-value store) and skip already-seen reviews. Sorts newest-first and stops at the first seen review. Ideal for scheduled monitoring.

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

Only keep reviews with rating >= this (1-5). 0 = no filter.

## `maxRating` (type: `integer`):

Only keep reviews with rating <= this (1-5). 0 = no filter.

## `productConcurrency` (type: `integer`):

How many products to scrape in parallel. Keep low to avoid anti-bot blocks.

## `requestDelayMs` (type: `integer`):

Polite delay added between GraphQL requests within a worker.

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

Proxy for the requests. Tokopedia is behind Akamai Bot Manager; if you get blocked, enable Apify Proxy (residential RESIDENTIAL group, country ID recommended).

## Actor input object example

```json
{
  "shopUrls": [
    "https://www.tokopedia.com/wahanakaryastore"
  ],
  "maxProductsPerShop": 0,
  "maxReviewsPerProduct": 0,
  "onlyProductsWithReviews": false,
  "reviewSort": "informative_score desc",
  "reviewsSince": "",
  "includeProductSummaries": true,
  "includeSellerReplies": true,
  "dedup": false,
  "minRating": 0,
  "maxRating": 0,
  "productConcurrency": 3,
  "requestDelayMs": 400,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `reviews` (type: `string`):

All scraped reviews and seller replies as JSON items.

## `productSummaries` (type: `string`):

Per-product aggregates (average rating, 1-5 star distribution). Present when 'Emit a per-product summary' is enabled.

## `runInConsole` (type: `string`):

Browse this run's output in a friendly interface.

# 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 = {
    "shopUrls": [
        "https://www.tokopedia.com/wahanakaryastore"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("auliax20/tokopedia-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 = { "shopUrls": ["https://www.tokopedia.com/wahanakaryastore"] }

# Run the Actor and wait for it to finish
run = client.actor("auliax20/tokopedia-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 '{
  "shopUrls": [
    "https://www.tokopedia.com/wahanakaryastore"
  ]
}' |
apify call auliax20/tokopedia-reviews --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,auliax20/tokopedia-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/LLhMdEyvLMzuqu8v8/builds/D9ZNHxiD9fR3AKSmG/openapi.json
