# Alibaba 1688 Supplier Ratings Scraper (`dami_studio/alibaba-1688-supplier-ratings-scraper`) Actor

1688.com supplier scorecards, no account needed: rating out of 5, five sub-scores, repeat-buyer rate, years on platform, factory or trader, audits, location. Look a company up by name or get every supplier behind a keyword. $0.40/1,000 - the lowest per-supplier price on Apify.

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

## Pricing

from $0.40 / 1,000 supplier returneds

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

## Alibaba 1688 Supplier Ratings Scraper

Pulls the **supplier scorecard** off **1688.com** — Alibaba's Chinese wholesale marketplace — for any
seller you can name, or for every seller behind a product keyword.

One row per supplier: the composite rating, all five sub-scores, the repeat-buyer rate, how long they
have been on the platform, whether they are a factory or a middleman, whether 1688 has audited them
on site, and where they are.

No login. No API key. No cookies to paste. No browser.

### Read this first — what the rows contain

This returns **ratings and scores, not written reviews.** There is no review text in the output,
because there is no route to it (details in "What this does not do" below). If you need buyer
comments in prose, this Actor is not it, and no amount of configuration will make it produce them.

It is also **1688.com, not Alibaba.com.** 1688 is Alibaba Group's domestic Chinese wholesale site —
the one sourcing agents actually buy from, priced in yuan, listings in Chinese. It is a different
marketplace from the English-language Alibaba.com export site, with different sellers.

### What you get, per supplier

| Field | Example |
|---|---|
| `supplierName` | 东莞市元拓橡塑制品有限公司 |
| `supplierId` | `b2b-22072902285003c713` |
| `supplierUrl` | https://m.1688.com/winport/b2b-22072902285003c713.html |
| `rating` / `ratingScale` | `4.0` / `5` |
| `ratingBreakdown.productDescription` | `4` |
| `ratingBreakdown.logistics` | `3.14` |
| `ratingBreakdown.responsiveness` | `3.5` |
| `ratingBreakdown.disputeHandling` | `5` |
| `ratingBreakdown.afterSales` | `3.67` |
| `repeatBuyerRate` / `repeatBuyerRatePercent` | `"37%"` / `37` |
| `yearsOnPlatform` | `7` |
| `businessType` / `businessTypeEnglish` | `生产加工` / `Manufacturer` |
| `isManufacturer` | `true` |
| `hasFactoryAudit` / `hasBusinessAudit` | `false` / `false` |
| `province` / `city` | `广东` / `东莞市` |
| `serviceTags` / `serviceTagsEnglish` | `["实商"]` / `["Verified real business"]` |
| `buyerProtections` | `["7天包换","48小时发货","诚e赊"]` |
| `matchedProduct` | the listing that surfaced them, with its own price, MOQ and sales figures |
| `matchedBy`, `searchQuery`, `scrapedAt` | how the row was found |
| `productsMatchedInThisRun` | `3` — how many of this seller's listings this run saw |

Chinese fields keep their Chinese values, because that is what 1688 prints and what you will need to
paste back into 1688. Where a short English gloss is safe, it sits in a parallel `…English` field.

#### One field depends on which mode you ran

`listedProducts` — the seller's **whole catalogue size** — is present **only on supplier-name
lookups**, and even there only when the result page came back essentially pure, meaning at least 80%
of the listings on it belonged to the target company. Below that the number would be counting other
sellers' listings too, so it is withheld rather than published wrong. Measured live: 14, 168, 199,
299, 827.

On keyword runs the key is **not in the row at all**. That is deliberate. In keyword mode 1688's
`found` counts listings matching the *keyword* across every seller, so there is no per-supplier
catalogue size to report; emitting `listedProducts: null` on every row would be a column that is
empty 100% of the time, which is worse than an absent key. Nothing else in the row changes between
modes — same scorecard, same profile, same `matchedProduct`.

`productsMatchedInThisRun` is not the same thing. It is how many of that seller's listings *this
particular run happened to see*, so it depends on your `maxItems` and your keyword, not on the
seller. It is always at least 1, in both modes. Use `listedProducts` for catalogue size; never use
`productsMatchedInThisRun` for it.

### Real field coverage

Two measurements, both counts off live data, neither estimated.

**A production run of this Actor: 300 suppliers in 93 seconds**, one keyword (保温杯), 300 rows, 300
distinct companies, zero duplicates, zero diagnostics.

**A wider crawl of 341 unique suppliers** across eight categories (phone cases, dresses, bluetooth
earphones, thermos flasks, trainers, LED lighting, cosmetics, pet supplies), which is the better guide
to how coverage varies between categories.

| Field | 300-row production run | 341-supplier crawl |
|---|---|---|
| `supplierId`, `supplierName`, `supplierUrl`, `supplierLoginId`, `supplierUserId` | 100% | 100% |
| `rating` | 100% | 100% |
| `ratingBreakdown` — all five sub-scores | 100% | 97.1–100% |
| `repeatBuyerRate` | 99.7% | 99.4% |
| `yearsOnPlatform` | 100% | 100% |
| `serviceTags`, `identityTags` | 100% | 100% |
| `buyerProtections` | 99.7% | 99.7% |
| `province`, `city` | 98.7% | 97.4% |
| `businessType` | 92.0% | 83.9% |
| `matchedProduct` | 100% | 100% |
| `productsMatchedInThisRun` | 100% | 100% |
| `listedProducts` | not emitted in keyword mode | not emitted in keyword mode |

`businessType` is the one field that genuinely varies by category — 92% on hardware and homeware, 84%
across the wider mix. Everything else holds above 97%.

Distribution over the 341-supplier crawl, so you know what the numbers look like before you buy any:
rating runs 3.5 to 5.0, median 4.5, mean 4.28; 313 of 341 are at 4.0 or above. Years on platform runs
1 to 19, mean 5.9. 73.9% are manufacturers (生产加工), 9.7% wholesalers (经销批发), 0.3% agents
(招商代理) and 16.1% publish no business type at all. 251 of 341 are in Guangdong. The production run
agreed closely: median 4.5, mean 4.36, 84% manufacturers.

`isVerifiedMember` was `true` on **341/341**. It is emitted for completeness, but it does not
discriminate: 1688 search only surfaces paid 诚信通 members, so every row has it.

Five fields that 1688 sends on every offer are **deliberately not emitted**, because they are zero on
every offer: `compositeScore`, `uvNum`, `mpRepateRate`, `tbShopSales`, `wwTimelyResponseRate30d`.
`compositeScore` is the trap — it looks like the rating and is 0 on all 341 sellers. The real rating
is `compositeNewScore`, which is what `rating` reads.

### Shop numbers vs product numbers

1688 mixes seller attributes and listing attributes into one flat object, and it is easy to publish a
per-listing number as if it described the company. This Actor does not.

The split was measured, not assumed: a keyword crawl was grouped by seller id and each field compared
across that seller's own listings. Nine sellers appeared more than once.

- **Constant across a seller's listings, 9/9** — published as supplier attributes: company name,
  province, city, business type, years on platform, all six rating figures, repeat-buyer rate,
  service and identity tags, both audit flags, store URL.
- **Different on every listing, 8/9** — published only inside `matchedProduct`: units sold, 30-day
  units, order count, that listing's repeat-buyer rate, buyer enquiries, 30-day revenue.

So `matchedProduct.revenue30DaysCny` is that **one listing's** 30-day revenue. It is not the
company's turnover, and it is not published as such.

### Two ways to use it

**Look up a supplier you already know.** Put the company name, exactly as 1688 prints it, into
`supplierNames`:

```json
{ "supplierNames": ["东莞市元拓橡塑制品有限公司", "深圳咕咚智能数码有限公司"] }
```

Tested on 6 randomly chosen suppliers: all 6 resolved, every returned listing belonged to the target
company, and the company was rank 1 every time. This is the only mode that carries `listedProducts`
(the seller's catalogue size).

**Find the suppliers behind a product.** Put a product term into `searchTerms` and get every distinct
seller whose listings match, deduplicated, ranked as 1688 ranked them:

```json
{ "searchTerms": ["保温杯"], "maxItems": 200, "minRating": 4, "manufacturersOnly": true }
```

Chinese terms match far more inventory than English ones — `手机壳` returns millions of offers where
"phone case" returns a few thousand. Both work.

`minRating` and `manufacturersOnly` are applied after the data comes back, so anything they drop is
**not charged**.

### What this does not do

- **No review text.** 1688 exposes no route to buyer comments that works without a logged-in account.
  24 plausible endpoint names were probed live (`mtop.1688.rate.getratelist`, `mtop.1688.offer.rate.list`,
  `mtop.alibaba.rate.list`, `mtop.1688.company.get`, `mtop.1688.credit.detail.get`, the whole
  `mtop.1688.wap.seo.*` family and more) and every one answered `FAIL_SYS_API_NOT_FOUNDED::请求API不存在`,
  against a control that answered `SUCCESS` in the same session. The storefront pages that render
  reviews are behind Alibaba's punish gate. Nothing here is invented to fill that gap.
- **Store URLs cannot be looked up.** A 1688 store URL carries the member id (`b2b-…`) or a shop
  subdomain, and neither can be turned back into a company. Every seller-id search parameter 1688
  accepts — `memberId`, `sellerMemberId`, `userId`, `companyId`, `sellerLoginId` — is silently
  ignored: with and without them the same 20 listings from 16 unrelated sellers came back. A store
  URL therefore returns an explanation, not a wrong row.
- **No contact details.** Phone, email and the WW chat handle are not in this data.
- **No supplier catalogue dump.** You get the seller's scorecard plus the one listing that surfaced
  them, not their whole product list.
- **No Alibaba.com.** Different site, different sellers.

### Limits, honestly

**Depth.** A keyword returns at most 2,000 listings — 1688 reports `found: 2000` for any broad term
and stops paginating there. In practice a page of 50 listings yields about 45 distinct sellers, so
roughly 1,800 suppliers is the ceiling for a single term. A real run pulled **300 distinct suppliers
from one keyword in 93 seconds** with no duplicates. Past that, go wide across terms rather than deep
on one.

**Rate limit — the real constraint, and the honest weak spot.** 1688 meters the search endpoint per
**exit address**. A spent address answers `FAIL_SYS_USER_VALIDATE` and keeps doing so for a good
while; the quota refills on its own but not quickly.

Nothing about the request changes that verdict — tested on a spent address, all in one session: a
brand-new keyword, an English keyword, API version 2.0, a different `appName`, a smaller page size,
all refused identically, while a *different* 1688 endpoint answered `SUCCESS` from the same address in
the same second. So it is the address plus that one endpoint, not the query and not a ban. Switching
gateway does not help either: `acs.m.taobao.com`, `h5api.m.taobao.com` and `h5api.m.tmall.com` all
serve the same 1688 API and all refuse an address that is already spent.

Data volume is cheap here — 300 suppliers is about seven API calls — so the constraint is finding a
clean address, not making many requests. The Actor walks its rented addresses, then the container's
own, then fresh datacenter sessions, trying a new one every few seconds. If 45 seconds go by with no
clean address it stops and writes an uncharged `BLOCKED` row rather than billing you for a fight it is
losing. That timer resets every time a page succeeds, so a run that is producing rows is never cut
short.

Roughly one datacenter address in three arrives already flagged even on a quiet day, and the shared
pools do get saturated. **If you are running this at volume, supplying your own proxies under Advanced
is the single change that helps most** — each address you add is another independent quota, and the
Actor will use only yours.

**It fails loudly.** Every failure mode writes a labelled, uncharged row: `BLOCKED` when the exits are
spent, `SUPPLIER_NOT_FOUND` when no company by that name is in the results (with the names that were
seen, so you can spot a typo), `ALL_FILTERED_OUT` when your own `minRating`/`manufacturersOnly` dropped
everything, `ALL_DUPLICATES` when a query only matched companies an earlier query already returned,
plus `NO_RESULTS`, `BAD_INPUT` and `LOOKUP_FAILED`. If 1688 changes its API response the Actor stops
with an error instead of quietly writing zero rows.

**The transport can be retired without notice.** This runs on 1688's own mobile JSON API, signed the
way 1688's mobile web client signs it, with an app key lifted from a versioned Alibaba CDN bundle.
Alibaba can change or retire that at any time. There is no contract here and no vendor behind it.

### Pricing

**$0.40 per 1,000 suppliers**, plus a $0.005 fee when the run starts.

That is **the cheapest per-supplier price for Alibaba / 1688 supplier data on the market**, and it
is a flat rate — no volume tiers, no plan gates, so the same $0.40 per 1,000 applies on the free
plan and on every paid plan alike.

| Suppliers | Cost (incl. the $0.005 start fee) |
|---|---|
| 1 | $0.0054 |
| 100 | $0.045 |
| 1,000 | $0.405 |
| 10,000 | $4.005 |

**What that claim does and does not cover.** It is about *supplier* rows — a scorecard with the
composite score, the five sub-scores, repeat-buyer rate, years on platform, factory-vs-trader
classification, audits and location. Plenty of Alibaba and 1688 tools bill a cheaper row that is a
*product*, a *review* or a generic `result`, and this Actor makes no claim to undercut those,
because a product row is not the same purchase. If what you need is a catalogue of listings rather
than a judgement about who you are buying from, a product scraper is the right tool and this is not
it.

One thing worth noticing when you cost a very small job: the $0.005 start fee dominates a
single-supplier run. Batch your look-ups — the per-row price is what decides anything from about a
hundred suppliers upwards.

You pay once per supplier returned. Sample rows, diagnostic rows, duplicates and anything your
filters drop are never charged — an empty run returns one clearly labelled uncharged sample row, a
run whose every input value was rejected (a store URL, say) returns a `BAD_INPUT` row per value
naming the reason plus that same uncharged sample row, and a run that 1688 blocks returns one
uncharged `BLOCKED` row.

### FAQ

**Does this scrape Alibaba.com or 1688.com?**
1688.com — Alibaba's Chinese-language domestic wholesale marketplace. Not the English Alibaba.com
export site.

**Does it return written buyer reviews?**
No. It returns 1688's numeric supplier scorecard: one composite rating out of 5 plus five sub-scores,
and the repeat-buyer rate. There is no review text, and no configuration produces any.

**What is the composite rating out of?**
5\. Across 341 measured suppliers it ran 3.5 to 5.0 with a median of 4.5. 1688 does not surface
low-rated sellers in search, so treat 4.28 as the population mean of what search returns, not of all
sellers on the platform.

**Can I look a supplier up by their store URL?**
No, and the Actor tells you so instead of guessing. Use the exact company name in `supplierNames`.
1688 ignores every seller-id parameter its search accepts, so there is no way to resolve a `b2b-…` id
back to a company.

**Do I need a Chinese IP or a 1688 account?**
Neither. The Actor ships with its own exit addresses and runs unauthenticated. Rented mainland-China
addresses were tried on an earlier project and were punished within 2-3 requests — geography is not
the constraint here.

**Why did my run stop early with a BLOCKED row?**
1688 meters per exit address, and every address the Actor had was already spent. Wait a while and
re-run, or supply your own proxies under Advanced — each one is another quota. You are not charged
for the failure. Pacing does not help: the limit is on how many calls an address has made, not how
fast it made them.

**What is `matchedProduct` for?**
Provenance. It is the listing that surfaced the seller, with that listing's own price, MOQ and sales
figures. Those numbers describe the product, not the company — they were measured to differ across a
seller's own listings on 8 of 9 sellers.

**Why is there no `listedProducts` in my rows?**
Most likely because you ran a keyword search. That field is the seller's catalogue size, and it only
exists when the query *was* the seller's own company name — put the name in `supplierNames` and it
appears. On keyword runs the key is left out of the row rather than written as `null`, so an empty
column never shows up in your export. It is also left out of a supplier-name row when the search page
that resolved that company was mixed with other sellers' listings, because the count would then not be
theirs.

**What is `productsMatchedInThisRun`?**
How many of that seller's listings this run happened to see before it hit your `maxItems`. It is a
property of your run, not of the supplier — do not read it as a catalogue size. `listedProducts` is
the catalogue size, on supplier-name lookups.

**Can I get their phone number or email?**
No. That data is not in this response and this Actor does not claim it.

**What does `repeatBuyerRate` mean?**
1688's 回头率 — the share of the shop's buyers who ordered again. It is a shop-level figure and was
identical across each seller's listings on 9 of 9 sellers checked.

# Actor input Schema

## `searchTerms` (type: `array`):

One product term per line. Every distinct seller whose listings match comes back as one row with their scorecard. Chinese matches far more inventory than English: 手机壳 returns millions of offers where "phone case" returns a few thousand. Both work.

## `supplierNames` (type: `array`):

The exact company name as 1688 prints it on the store page, in Chinese, e.g. 东莞市元拓橡塑制品有限公司. One per line. Store URLs do NOT work here and are rejected with an explanation: 1688 has no supplier endpoint, and every seller-id search parameter it accepts is silently ignored, so a b2b-… id cannot be turned back into a company.

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

Optional. Paste 1688 search pages such as https://s.1688.com/selloffer/offer\_search.htm?keywords=手机壳 — the keyword is read out of the URL and treated like a product keyword.

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

Hard cap on supplier rows across all queries (1-1000). You are charged once per supplier returned. Suppliers dropped by the filters below are never charged.

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

Optional. Drop suppliers rated below this on 1688's 0-5 composite score. Applied after the data comes back, so filtered-out suppliers cost you nothing.

## `manufacturersOnly` (type: `boolean`):

Keep only sellers 1688 classifies as 生产加工 (a factory), dropping wholesalers, distributors and trading agents. Measured over 341 suppliers: 73.9% manufacturers, 9.7% wholesalers, 16.1% with no business type published.

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

Pause between API calls. 1688 meters by how many calls an exit address has made rather than how fast, so this mostly affects run time — the fix for a BLOCKED run is more addresses, not more waiting.

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

Optional. The Actor ships with its own exit addresses; leave this alone unless you want to run through your own proxies, which is worth doing for high-volume runs because 1688's per-address quota refills slowly.

## Actor input object example

```json
{
  "searchTerms": [
    "手机壳"
  ],
  "supplierNames": [],
  "startUrls": [],
  "maxItems": 50,
  "requestDelayMs": 1200,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per supplier in the default dataset: rating out of 5 with its five sub-scores, repeat-buyer rate, years on the platform, factory or trader, audits and location. Empty or blocked runs return a single uncharged 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 = {
    "searchTerms": [
        "手机壳"
    ],
    "supplierNames": [],
    "startUrls": [],
    "maxItems": 50,
    "manufacturersOnly": false,
    "requestDelayMs": 1200,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/alibaba-1688-supplier-ratings-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 = {
    "searchTerms": ["手机壳"],
    "supplierNames": [],
    "startUrls": [],
    "maxItems": 50,
    "manufacturersOnly": False,
    "requestDelayMs": 1200,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/alibaba-1688-supplier-ratings-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 '{
  "searchTerms": [
    "手机壳"
  ],
  "supplierNames": [],
  "startUrls": [],
  "maxItems": 50,
  "manufacturersOnly": false,
  "requestDelayMs": 1200,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call dami_studio/alibaba-1688-supplier-ratings-scraper --silent --output-dataset

```

## MCP server setup

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