# 1688 Reviews Scraper - Ratings, Photos & SKUs (`dami_studio/1688-reviews-scraper`) Actor

Scrape buyer reviews from any 1688.com product: star rating, review text, photos, the SKU bought, order quantity, buyer nickname and history, publish date. Product URL or ID in, JSON out. No account, no cookies. $2.00 per 1,000 reviews, flat rate, plus a $0.004 start fee.

- **URL**: https://apify.com/dami\_studio/1688-reviews-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** E-commerce, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 reviews

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/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

## 1688 Reviews Scraper (1688.com product review API)

Pulls buyer reviews off a 1688.com product listing and returns them as clean JSON: star rating,
review text, photos, the exact SKU the buyer ordered, order quantity, buyer nickname and buying
history, and the publish date. Give it a product URL or a product ID.

No 1688 account. No cookies to paste. No captcha solving. No browser.

**$2.00 per 1,000 reviews**, plus a $0.004 start fee. A flat rate — no volume tiers to unlock and no
plan gates, and you are charged only for reviews actually returned.

***

### What you get

One row per review. From a real run of 246 reviews across four products:

| Field | Filled | What it is |
|---|---|---|
| `reviewId` | 100% | 1688's own review id |
| `productId`, `productUrl` | 100% | The product the review belongs to |
| `rating` | 100% | 1 to 5 stars |
| `reviewText` | 100% | The review body, in Chinese, exactly as posted |
| `isAutoReview` | 100% | 1688 posted this itself because the buyer never rated — see below |
| `isTemplateText` | 100% | The text is 1688 boilerplate, not something the buyer typed |
| `publishedAt`, `createdAt` | 100% | ISO 8601, converted from Beijing time |
| `images`, `imageCount` | 3.3% / 100% | Full-size photo URLs. Most 1688 reviews have no photo |
| `quantity`, `unit` | 100% | How many the buyer ordered, and in what unit (个, 件, 箱…) |
| `skuSpec`, `skuSpecs` | 100% | The variant(s) bought — colour, size, model — as text and as objects |
| `buyerNick`, `buyerLevel` | 100% | Masked nickname (`q**莉`) and 1688 buyer tier (`L0`–`L6`) |
| `isAnonymous`, `isRepeatCustomer` | 100% | Posted anonymously; has bought from this seller before |
| `buyerOrdersRated`, `buyerGoodRatings` | 100% | How many orders this buyer has rated overall, and how many positively |
| `buyerAvatarUrl` | 100% | Profile picture |
| `sellerNick`, `sellerLoginId` | 100% | The seller being reviewed |
| `productTotalReviews` | 100% | Total reviews on the product |
| `productReviewsWithText` | 100% | How many of those have written content |
| `productAutoReviewCount` | 100% | How many are 1688's own auto-posted defaults |
| `productGoodRatePercent`, `productStarGrade` | 100% | The product's own good-rate (e.g. `99.9`) and star grade |
| `reviewFilter`, `page`, `position`, `scrapedAt` | 100% | Run metadata |

Those percentages are measured, not estimated. `images` really is 3.3% — on the four products
tested, 8 of 246 reviews carried a photo, which matches 1688's own "with photos" counter exactly.
Filter to written reviews only and it rises to about 9%; ask for photos only and it is 100% by
definition.

#### Read `isAutoReview` and `isTemplateText` before you average anything

1688 fills in a review for buyers who never write one, and the raw star ratings are close to
useless without accounting for it. On one product: **2,511 reviews, of which 2,455 were auto-posted
defaults and 56 had real content.** Two different templates show up:

- `评价方未及时做出评价,系统默认好评!` — the timeout default. 1688 flags this itself, and it comes
  back as `isAutoReview: true`.
- `该用户觉得商品非常赞，给出了五星好评` — what you get when a buyer taps five stars and writes
  nothing. 1688 does **not** flag this one.

`isTemplateText` covers both. Set the input filter to **Written text only** to get just the reviews
somebody actually typed — that is 1688's own tab, and on the product above it returns 56 rows
instead of 2,511.

### Input

```json
{
  "productUrls": ["https://detail.1688.com/offer/927875250705.html"],
  "maxReviewsPerProduct": 100,
  "reviewFilter": "withText"
}
```

- **productUrls** — one per line. A product URL, a bare product ID (`927875250705`), or a 1688
  review page URL. The review page URL already contains the seller login id, which saves the actor
  a lookup and makes the run noticeably faster.
- **maxReviewsPerProduct** — 1 to 4000. You are charged per review returned.
- **reviewFilter** — 1688's own review tabs, all six verified live:
  `all`, `withText` (有内容), `withPhotos` (有图), `positive` (好评), `neutral` (中评),
  `negative` (差评). On the test product these returned 2,511 / 56 / 6 / 2,508 / 2 / 1 rows, matching
  1688's own counters on every tab.
- **requestDelayMs** — advanced. Raise it if a run stops early with a `BLOCKED` row.
- **proxyConfiguration** — advanced. The actor brings its own rotating datacenter exit addresses and
  you do not need to supply any. If you do supply **custom proxy URLs**, they are used exactly as
  given, in the order given, for every request. Metered Apify proxy groups (Residential, SERP) are
  not offered: asking for one gets you datacenter addresses plus an uncharged `PROXY_GROUP_IGNORED`
  row saying so. 1688's mobile API is not geo-gated, so this costs you nothing in coverage.

### What this does NOT do

- **It is not a product search.** You cannot give it a keyword. It takes product URLs and IDs only.
- **It is not a product-detail scraper.** No prices, no MOQ, no supplier profile. Reviews only.
- **It does not translate.** Reviews come back in the original Chinese, unmodified.
- **It cannot see reviews 1688 hides.** Only what the public review page serves is available; there
  is no account behind this, so there is no privileged view.
- **It does not do shop-wide reviews.** One product at a time.
- **Photos are rare.** 3.3% of rows had one in testing. That is 1688, not the scraper.

### Limits, measured

- **Ten reviews per request.** 1688 clamps the page size — asking for 20, 50, 100 or 200 all return
  exactly 10. So 500 reviews is 50 requests, and there is no way to buy that down.
- **Depth is bounded by the product, not by a cap.** A 2,511-review product served page 251 fine and
  answered page 300 with `SYSTEM_ERROR`, which is exactly where the reviews run out. 400 consecutive
  unique reviews were pulled with no repeats and no throttling.
- **Speed, and how much it varies.** 250 reviews from one product took **32 seconds** on one cloud
  run and **120 seconds** on another with identical input. Both are real; the difference is how fast
  the exit addresses happen to be that minute, and a 250-review pull is 25 sequential requests with a
  configurable gap between them. A 5-review run finishes in 4–7 seconds off a warm seller cache. Plan
  for the slow end, not the fast one.
- **The counts line up.** Asked for written reviews only on a product whose own counter says 7, the
  run returned exactly 7. Same for the photo tab, the neutral tab and the negative tab.
- **Rate limits.** Roughly one in five fresh exit addresses arrives already flagged by 1688 and is
  discarded on its first call. The actor rotates automatically. Across a 246-review run it spent 3
  rotations. If everything is flagged at once you get an uncharged `BLOCKED` row, and it clears
  within minutes.
- **The seller login id.** 1688's review API requires the seller's login name alongside the product
  id, and it is not derivable from the product id. It is read once per product from the mobile
  product page — the only public place 1688 serves it. See below for how that is handled, because it
  is the one part of this actor 1688 actively fights.

### The seller lookup, and why it used to lose

The review API will not answer without the seller's login name, and the only page that carries it
sits behind Alibaba's per-IP captcha gate. Measured over 24 fresh datacenter exits, each of which got
its own address: **11 served the 196 KB page, 12 answered a ~2 KB captcha stub, 1 never answered at
all.** Roughly one attempt in two loses, and the loss is decided by the address, not by the request —
so retrying the same address is pointless.

The old build tried five addresses one after another inside a 30-second budget, and minted an API
token it did not need before each one. A couple of slow exits could eat the whole budget, and the run
came back empty. Three things fixed it:

1. **Addresses are raced, not queued.** Four exits are tried at once and the first good page wins;
   the losers are aborted before their 196 KB transfers. Up to five waves — twenty addresses.
2. **Every one of those addresses is a free datacenter exit.** At the measured 11-in-24 success rate
   a single wave of four already lands ~95% of the time and five waves take that past 99.9%, so the
   lookup never needs a metered proxy group to succeed. It does not have one available: this actor
   reaches no per-gigabyte egress at all, on any path, however it is configured.
3. **The answer is cached across runs.** A product's seller never changes, so the first run that
   resolves one writes it to a named key-value store and every later run on that product skips the
   lookup completely — no fetch, no gate, no failure mode. A cached id that 1688 later rejects is
   dropped and looked up again.

Measured on the same product, same input, cloud runs only, old build and new build interleaved so
neither got a kinder half-hour:

| | runs that returned reviews |
|---|---|
| old build | **25 / 32** — seven runs came back empty |
| new build, cache deleted before every run (full cold lookup every time) | **24 / 24** |
| new build, cache left alone (what you actually get) | **8 / 8**, and seven of the eight never fetched the page at all |

Median cold lookup 2.4 s; with the cache warm the whole run finishes in 4–7 s.

If it still loses, you get an uncharged `SELLER_LOOKUP_FAILED` row that tells you how many addresses
were tried, whether the product exists and how many reviews are waiting behind the retry. Pasting the
product's **review page URL** instead of the product URL skips the lookup entirely — it already
carries `sellerLoginId=`.

### Reliability note

This runs on 1688's own mobile API (`h5api.m.1688.com`), using request shapes lifted from the
versioned component bundles 1688 ships to its own web app. Alibaba can retire or rename those at any
time without notice. When that happens the actor fails loudly with the API's error string in an
uncharged diagnostic row — it does not quietly return zero rows and bill you for the privilege.

### Billing

- `review` — $0.002 per review returned. **$2.00 per 1,000.**
- Actor start — $0.004 per run.

Sample rows, diagnostics, failed lookups and blocked runs are **never** charged. An empty input
returns one clearly labelled sample row and charges nothing beyond the start fee (verified: a run
with `{}` charged 0 review events).

The start fee is the one thing an Actor cannot waive: Apify charges `apify-actor-start` itself when
the run starts, before any of this code executes, so a run that ends in `SELLER_LOOKUP_FAILED` still
costs you $0.004. That is exactly why the lookup was rebuilt rather than merely apologised for.

### FAQ

**Do I need a 1688 account or cookies?**
No. Nothing to log into, nothing to paste, no captcha to solve.

**Can I search 1688 by keyword with this?**
No. This actor takes product URLs or IDs. Keyword search is a different job.

**Why are so many reviews five stars with the same text?**
Because 1688 writes them. Buyers who never rate get an automatic five-star default. Use the
`withText` filter, or drop every row where `isTemplateText` is true.

**Are the reviews in English?**
No — they are in Chinese, exactly as posted. Nothing is translated or paraphrased.

**How many reviews can I get from one product?**
All of them. The deepest product tested had 2,511 and paged cleanly to the end. Set
`maxReviewsPerProduct` to whatever you want to pay for.

**Can I get reviews with photos only?**
Yes, set `reviewFilter` to `withPhotos`. Be aware it is a small slice — 6 of 2,511 on the test
product.

**What does `skuSpec` look like?**
`颜色: 磨砂半透明, 适用型号: iphone16Pro | 颜色: 黑色, 适用型号: iPhone12Pro Max` — the variants that
buyer ordered. `skuSpecs` is the same thing as an array of objects, if you would rather not parse
a string.

**What happens if 1688 blocks the run?**
You get an uncharged `BLOCKED` row explaining what happened and how many reviews came back before
it. Re-run a few minutes later; the per-address quota refills quickly.

**Can I use this with Make, Zapier, or an LLM agent?**
Yes. It is a standard Apify Actor with a JSON input and a JSON dataset output, so anything that can
call the Apify API can drive it.

# Actor input Schema

## `productUrls` (type: `array`):

One per line. A product URL such as https://detail.1688.com/offer/927875250705.html, a bare product ID such as 927875250705, or a 1688 review page URL (which already carries the seller login id, saving one lookup).

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

Hard cap per product (1-4000). 1688 serves ten reviews per request, so 100 reviews is ten requests. You are charged per review returned.

## `reviewFilter` (type: `string`):

1688's own review tabs. Most 1688 reviews are auto-posted five-star defaults from buyers who never wrote anything — "Written text only" is usually what you actually want.

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

1688 rate-limits per exit address. The actor already spreads requests across several addresses and rotates on a block; raise this if a run stops early with a BLOCKED row.

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

Optional. The actor supplies its own rotating datacenter exit addresses, which is what 1688's mobile API wants — leave this alone unless you want to run through proxies of your own. Custom proxy URLs are used exactly as given. Metered Apify groups (Residential, SERP) are not offered here and are replaced with datacenter addresses, with an uncharged notice row explaining the swap.

## Actor input object example

```json
{
  "productUrls": [
    "https://detail.1688.com/offer/927875250705.html"
  ],
  "maxReviewsPerProduct": 100,
  "reviewFilter": "all",
  "requestDelayMs": 800,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset row per buyer review: star rating, review text with flags for template and auto-generated wording, photo count, purchased SKU, order quantity, buyer nickname and buying history, publish date, and the product's own review counts and good-rate. Empty input, a blocked fetch or a product with no reviews writes an uncharged sample or diagnostic row instead.

# 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 = {
    "productUrls": [
        "https://detail.1688.com/offer/927875250705.html"
    ],
    "maxReviewsPerProduct": 100,
    "reviewFilter": "all",
    "requestDelayMs": 800,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/1688-reviews-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 = {
    "productUrls": ["https://detail.1688.com/offer/927875250705.html"],
    "maxReviewsPerProduct": 100,
    "reviewFilter": "all",
    "requestDelayMs": 800,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/1688-reviews-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 '{
  "productUrls": [
    "https://detail.1688.com/offer/927875250705.html"
  ],
  "maxReviewsPerProduct": 100,
  "reviewFilter": "all",
  "requestDelayMs": 800,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call dami_studio/1688-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/1688-reviews-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/jdbKxv4YzC5jdtQ19/builds/c2gp2KhPmlqdSLhqd/openapi.json
