# 1688.com Products Scraper (`nice_dev/1688-products-scraper`) Actor

Scrape 1688.com wholesale products by keyword, region or offer ID: tiered prices, MOQ, sales, supplier ratings, factory profile. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/nice_dev/1688-products-scraper.md
- **Developed by:** [Nice Dev](https://apify.com/nice_dev) (community)
- **Categories:** E-commerce, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.29 / 1,000 products

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

### 🛒 What is 1688.com Products Scraper?

**1688.com Products Scraper** extracts **wholesale products from [1688.com](https://www.1688.com)**, China's largest B2B marketplace: **title, unit price and bulk price tiers, minimum order quantity (MOQ), units sold, supplier, region and supplier service scores**, for any keyword, supplier region, search URL or offer ID. It works as a **1688 API alternative**: run it on a schedule, call it from your code, or plug it into Make, Zapier or n8n.

Type a **keyword** (`手机壳` or `phone case`), pick a **supplier region** if you want one, click **Start**, and download the products in JSON, CSV or Excel. No login, no 1688 account, nothing to set up. Built for **product sourcing, dropshipping, supplier research and price monitoring**.

### 📋 What data can you extract from 1688.com?

One item per product, 60 fields:

| Category                      | What you get                                                                                                                |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| 🏷️ **Product**                | title (in Chinese, as on 1688), link, offer ID, main photo, category — `iphone17promax手机壳…`                              |
| 💰 **Price and MOQ**          | unit price in yuan, quantity price tiers, promotion price flag, minimum order, selling unit — `9.8 CNY from 1 piece`        |
| 📈 **Sales**                  | units sold, order count, "want to buy" count, product repeat-purchase rate — `已售500+件` = 500                             |
| 🏭 **Supplier**               | company name, shop link, member ID, years on 1688, province and city, business type (manufacturer, wholesaler…)            |
| ⭐ **Supplier trust**         | 6 service scores (overall, goods, logistics, disputes, returns, consultation), repeat-buyer rate, factory and company audits |
| 🎖️ **Badges**                 | promotions, service badges, selling points, sponsored flag, link to the same product from other suppliers                  |
| 📦 **Full product page**      | add-on: every photo, video, attributes, variants (SKU) with price and stock, stock, weight, ships from, delivery days       |
| 🏢 **Factory profile**        | add-on: founding date, staff, production equipment, certifications, ranking badges, chat response rate                      |
| 💬 **Buyer reviews**          | add-on: stars, text, date, variant and quantity bought, photos, plus a summary of all the product's ratings                 |
| 🔔 **Price tracking**         | option: new product or price drop / rise, previous price, change in %, price history                                        |
| 🔎 **Search**                 | keyword and region that found the product, rank in the results, results page, time it was read                             |

Every field, with an example, is listed in the **Output** section below.

The search results already give the price tiers, the sales and the supplier's service scores. The **Full product page**, **Factory profile**, **Buyer reviews**, **Market statistics** and **price tracking** are add-ons: each one is off by default and charged only when you tick it.

### ✅ Why use 1688.com Products Scraper?

- 🧲 **Every 1688 filter in one form**: price range, maximum MOQ, supplier region, supplier tier, business type, dropshipping (一件代发), free shipping (包邮), ships within 48 h, one product per supplier — plus filters 1688 does not have: minimum service score, audited factories only, no sponsored results, excluded words.
- 🗺️ **Several keywords × several regions in one run**: every keyword is searched in every province or city you list, up to 500 per run.
- 📈 **More than 2,000 products per search**: 1688 shows at most 2,000 products per search; above that, the Actor splits the search into price ranges by itself.
- ⭐ **Supplier service scores in every row**: the 6 service scores and the repeat-buyer rate come with each product, without an add-on.
- 🧩 **Nothing twice**: pagination is automatic, and a product found by several searches is saved — and charged — once.
- 🔔 **Monitoring and price tracking**: tick **Only new products**, schedule the Actor, and each run returns only what it has never delivered — and, if you want, the products whose price moved since your last run.
- 🧾 **Add-ons à la carte**: product page, factory profile, buyer reviews and market statistics, each off by default.
- 🔌 API, scheduling, monitoring, integrations (Make, Zapier, n8n, Google Sheets…), proxy rotation and JSON/CSV/Excel export via the Apify platform.

### 🚀 How to scrape 1688.com

1. Create a free Apify account.
2. Open **1688.com Products Scraper** and type a **Search keyword** (e.g. `手机壳`, or `phone case` in English).
3. Optional: add a **Supplier region** (e.g. `广东`), more keywords and regions, filters — or paste 1688 search URLs or product URLs into **Start URLs**, or offer IDs into **Offer IDs**.
4. Set **Max products** (100 by default, 0 = no limit) — and **Max products per search** when you run several searches — then click **Start**.
5. Download the dataset in JSON, CSV, Excel or via API.

### 💰 How much does it cost to scrape 1688.com?

This Actor uses **pay per event** pricing: you pay for what you get, and the prices of each event are in the **Pricing** tab. What is charged:

- each **product** saved in the dataset;
- each **full product page** (with **Full product page**, and for every product read by **Offer IDs** or by a pasted product URL) — only when the page was really read;
- each **factory profile** (with **Factory profile**), once per supplier;
- each **buyer review** delivered (with **Include buyer reviews**);
- each **market statistics sheet**, one per search (with **Market statistics per search**);
- each **product that comes back for its price** (with **Also products whose price changed**), on top of the product itself;
- a small fee per run start, and a small fee for each product that a filter of the Actor checks and drops (`filter-check`).

A product already delivered, with **Only new products**, is neither saved nor charged. Platform usage (compute, proxy) is included in the price.

### ⚙️ Input

A simple search:

```json
{
    "query": "手机壳",
    "maxItems": 200
}
```

Several keywords × several regions, with a cap per search and site filters:

```json
{
    "searchQueries": ["手机壳", "数据线"],
    "locations": ["广东", "浙江"],
    "maxItemsPerQuery": 100,
    "sortBy": "bestSelling",
    "priceMax": 20,
    "dropshipOnly": true
}
```

Products you already know, by offer ID (each one is read from its product page):

```json
{
    "offerIds": ["1003563980252"],
    "includeSupplierDetails": true
}
```

A daily monitor: only the new products, plus the products whose price moved by 5 % or more:

```json
{
    "query": "手机壳",
    "location": "深圳",
    "onlyNew": true,
    "stateKey": "phone-cases-shenzhen",
    "includePriceChanges": true,
    "minPriceChangePercent": 5
}
```

Every add-on ticked:

```json
{
    "query": "蓝牙耳机",
    "maxItems": 50,
    "extractDetails": true,
    "includeSupplierDetails": true,
    "includeReviews": true,
    "maxReviewsPerProduct": 10,
    "reviewFilter": "bad",
    "includeMarketStats": true
}
```

Or with your own search URLs:

```json
{
    "startUrls": [{ "url": "https://s.1688.com/selloffer/offer_search.htm?keywords=%E6%89%8B%E6%9C%BA%E5%A3%B3" }],
    "maxItems": 500
}
```

| Field | Notes |
| --- | --- |
| `query`, `searchQueries` | Keyword, in Chinese for the best results (`手机壳`) or in English (`phone case`); `searchQueries` adds more keywords (one search each). Ignored when `startUrls` is set. |
| `location`, `locations` | Supplier province or city, in Chinese as on 1688: `广东`, `浙江`, `深圳`, `东莞`. A city is searched inside its province; empty = all of China. Every keyword is searched in every region (max 500 searches per run). |
| `startUrls` | 1688 search URLs (`https://s.1688.com/selloffer/offer_search.htm?keywords=%E6%89%8B%E6%9C%BA%E5%A3%B3`: keyword and supported filters are read from the URL, pagination is automatic) or product URLs (`https://detail.1688.com/offer/1003563980252.html`, read from its product page: the **Full product page** price applies). The sort order and the supplier filters of the form are added to a search URL that does not already carry them (a filter already in the URL wins); the other filters and caps apply to every product. Max 1,000 URLs. |
| `offerIds` | 1688 product IDs (`1003563980252`). Each one is read from its product page, so the full product page is charged. Can be combined with keywords; to read only these IDs, empty **Search keyword** (the form pre-fills one). |
| `maxItems` | Products to save for the whole run, after deduplication and filters (`0` = no limit). |
| `maxItemsPerQuery` | Cap for EACH search (keyword × region, or search URL); `0` = no per-search cap. |
| `sortBy` | `relevance` (default), `bestSelling`, `priceAsc` or `priceDesc`. |
| `priceMin`, `priceMax` | Unit price range in Chinese yuan, e.g. `5` to `20`. |
| `minOrderQuantity` | Maximum minimum order: only products you can buy in that small a quantity, e.g. `10`. |
| `merchantType` | 1688 supplier label: `any`, `superFactory`, `verifiedMerchant` or `sourceFlagship`. |
| `businessType` | `any`, `manufacturer`, `wholesaler`, `agent` or `service`. |
| `dropshipOnly`, `freeShippingOnly`, `ships48hOnly`, `onePerSupplier` | 1688 filters: dropshipping (一件代发), free shipping inside China (包邮), ships within 48 hours, one product per supplier (more different suppliers in the same number of results; when a search is split into price ranges above 2,000 products, one product per supplier in each range). |
| `extractDetails` | Add-on, off by default: open each product page for every photo, video, attributes, variants, stock, weight, shipping origin, delivery promise and services. |
| `includeSupplierDetails` | Add-on, off by default: the supplier's factory profile, read once per supplier. |
| `includeMarketStats` | Add-on, off by default: one sheet of figures per search (prices, MOQ, suppliers, top provinces, sales), in the MARKET_STATS record of the key-value store and in the Output tab. |
| `includeReviews`, `maxReviewsPerProduct` | Add-on, off by default: the buyer reviews inside each product row, up to 20 per product by default. |
| `reviewFilter` | 1688's own review filter: `all`, `photos`, `good`, `medium` or `bad`. |
| `reviewMinRating`, `reviewMaxRating` | Stars to keep, from `1` to `5` (e.g. max `2` for the complaints). |
| `reviewKeyword` | Keep only the reviews whose text contains this word (`质量`, `broke`). |
| `reviewPostedAfter` | Keep only the reviews written since a date (`2026-03-01`) or a period (`30 days`, `3 months`). |
| `excludeKeywords` | Drop the products whose title contains one of these words (`二手`); case and accents ignored. |
| `minRating` | Minimum overall service score of the supplier, from 0 to 5 (e.g. `4.5`); products of a search without a score are dropped. The score comes from the search results: a product pasted by ID or product URL is not checked by this filter. |
| `verifiedOnly`, `excludeAds` | Only suppliers whose factory was inspected on site (深度验厂 / 实地验厂; read from the search results, so a product pasted by ID or product URL is not checked by it); drop the sponsored results 1688 mixes in. |
| `onlyNew`, `stateKey`, `resetState` | Monitoring: only the products never delivered under this memory key (`phone-cases-guangdong`); `resetState` forgets the memory. |
| `includePriceChanges`, `minPriceChangePercent` | Option, off by default (needs `onlyNew`): also the products already delivered whose price moved by at least this many % (3 by default). |
| Advanced | `proxyConfiguration` (Apify proxy by default, included in the price; the residential proxy is not available), `maxConcurrency`, `maxRequestsPerMinute`, `minRequestIntervalMs`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

A real product from a test run (with **Include buyer reviews**; one review of two shown):

```json
{
    "id": "1003563980252",
    "url": "https://detail.1688.com/offer/1003563980252.html",
    "title": "iphone17promax手机壳简约磨砂肤感磁吸商务防摔适用苹果11保护套",
    "price": 9.8,
    "isPromoPrice": false,
    "currency": "CNY",
    "priceTiers": [
        { "minQuantity": 1, "maxQuantity": 299, "price": 9.8 },
        { "minQuantity": 300, "maxQuantity": 2999, "price": 9.5 },
        { "minQuantity": 3000, "maxQuantity": null, "price": 8 }
    ],
    "minOrderQuantity": 1,
    "unit": "个",
    "soldCount": 500,
    "soldText": "已售500+件",
    "orderCount": 10,
    "wantBuyCount": null,
    "repurchaseRate": null,
    "imageUrl": "https://cbu01.alicdn.com/img/ibank/O1CN01WZKX741OFCWMseb6g_!!3872131675-0-cib.jpg",
    "images": ["https://cbu01.alicdn.com/img/ibank/O1CN01WZKX741OFCWMseb6g_!!3872131675-0-cib.jpg"],
    "tags": ["退货包运费", "先采后付"],
    "serviceTags": ["深度验商"],
    "sellingPoints": [],
    "isAd": false,
    "sameDesignUrl": "https://s.1688.com/selloffer/similar_search.html?offerIds=1003563980252&imageAddress=https%3A%2F%2Fcbu01.alicdn.com%2Fimg%2Fibank%2FO1CN01WZKX741OFCWMseb6g_%21%213872131675-0-cib.jpg&scene=similar_search&postCatPaths=1046694%201046693%207&sameDesignEnablefalse",
    "supplierName": "深圳市亿佳合兴科技有限公司",
    "supplierLoginId": "深圳亿佳合兴科技有限公司",
    "supplierMemberId": "b2b-38721316754ec7c",
    "supplierUrl": "https://shop764420m281617.1688.com",
    "supplierYears": 9,
    "province": "广东",
    "city": "深圳市",
    "businessType": "生产加工",
    "isSuperFactory": null,
    "isFactoryAudited": false,
    "isBusinessAudited": true,
    "auditReportUrl": "https://r.1688.com/auth/fcaReport.htm?_input_charset=utf8&loginId=%E6%B7%B1%E5%9C%B3%E4%BA%BF%E4%BD%B3%E5%90%88%E5%85%B4%E7%A7%91%E6%8A%80%E6%9C%89%E9%99%90%E5%85%AC%E5%8F%B8",
    "isVerifiedMerchant": null,
    "supplierRepurchaseRate": 0.57,
    "serviceScores": {
        "overall": 4,
        "goods": 3.67,
        "logistics": 3.14,
        "disputes": 4,
        "returns": 4,
        "consultation": 3.5
    },
    "attributes": [],
    "skus": [],
    "videoUrl": null,
    "stock": null,
    "shipsFrom": null,
    "deliveryDays": null,
    "services": [],
    "descriptionUrl": null,
    "categoryId": null,
    "topCategoryId": null,
    "weightKg": null,
    "mixWholesale": null,
    "factory": null,
    "reviewSummary": {
        "goodRate": 1,
        "grade": 5,
        "total": 2,
        "withPhotos": 1,
        "good": 2,
        "medium": null,
        "bad": null,
        "topics": []
    },
    "reviews": [
        {
            "reviewId": "38904108462",
            "rating": 5,
            "text": "The quality is very good and the cooperation is very pleasant.",
            "date": "2026-01-14T07:09:59.000Z",
            "variant": "颜色: 橙色, 适用型号: iPhone 17promax | 颜色: 灰色, 适用型号: iPhone 17promax | 颜色: 蓝色, 适用型号: iPhone 17promax | 颜色: 黑色, 适用型号: iPhone 17promax",
            "quantity": 4,
            "quantityUnit": "个",
            "images": ["https://img.alicdn.com/imgextra/i1/O1CN01heX47Q1CjdSPppJ3B_!!4611686018427384725-0-rate.jpg"],
            "buyerNick": "匿名购买",
            "buyerLevel": "L3",
            "province": null,
            "isAnonymous": true
        }
    ],
    "changeType": null,
    "previousPrice": null,
    "priceChangePercent": null,
    "priceHistory": [],
    "searchQuery": "手机壳",
    "searchLocation": null,
    "position": 2,
    "searchUrl": "https://s.1688.com/selloffer/offer_search.htm?keywords=%E6%89%8B%E6%9C%BA%E5%A3%B3&beginPage=1",
    "scrapedAt": "2026-10-18T17:30:32.872Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel.

#### All 60 fields

| Fields | What you get |
| --- | --- |
| `id`, `url`, `title` | **Product**: offer ID, product page, title in Chinese (search highlights removed) |
| `price`, `isPromoPrice`, `currency` | **Price**: unit price for the minimum order, in yuan (`9.8`, `CNY`); `isPromoPrice` = a limited-time (限时价), after-coupon (券后价) or after-discount (折后价) price |
| `priceTiers`, `minOrderQuantity`, `unit` | quantity breaks `{minQuantity, maxQuantity, price}`, smallest quantity you can order, selling unit (个, 件, 套…) |
| `soldCount`, `soldText`, `orderCount`, `wantBuyCount`, `repurchaseRate` | **Sales**: units sold as a number (`已售1.7万+件` = 17000) and as shown, order count, "want to buy" count (product page), product repeat-purchase rate (0-1) |
| `imageUrl`, `images` | main photo; every gallery photo with the product page, the main photo otherwise |
| `tags`, `serviceTags`, `sellingPoints` | **Badges**: promotions, supplier service badges, short selling points |
| `isAd`, `sameDesignUrl` | sponsored result (null for a product read from its own page), 1688 search for the same product from other suppliers |
| `supplierName`, `supplierLoginId`, `supplierMemberId`, `supplierUrl`, `supplierYears` | **Supplier**: company name, shop name, member ID, shop link, years of paid 1688 membership |
| `province`, `city`, `businessType` | supplier province and city, kind of company (生产加工 manufacturer, 经销批发 wholesaler, 招商代理 agent, 商业服务 services) |
| `isSuperFactory` | true only when the search was restricted to super factories (`merchantType`); null otherwise |
| `isVerifiedMerchant` | true when the search was restricted to verified merchants (`merchantType`) or 1688 flags it; null when the result does not say |
| `isFactoryAudited`, `isBusinessAudited`, `auditReportUrl` | **Supplier trust**: factory inspected on site, company inspected by 1688, link to the inspection report |
| `supplierRepurchaseRate`, `serviceScores` | share of the shop's buyers who come back (0-1); 1688 service scores (0-5): overall, goods, logistics, disputes, returns, consultation |
| `attributes`, `skus` | **Full product page**: attributes `{name, value}` (material, model, style…); variants with `skuId`, `name`, `specs`, `price`, `stock`, `imageUrl` |
| `videoUrl`, `stock`, `weightKg`, `mixWholesale` | product video, units available, weight of one unit in kg, variants can be mixed to reach the MOQ (混批) |
| `shipsFrom`, `deliveryDays`, `services` | shipping origin, promised days before shipping, guarantees (free return shipping, late-shipment compensation…) |
| `descriptionUrl`, `categoryId`, `topCategoryId` | link to the long description (images, size charts), 1688 category and top-level category |
| `factory` | **Factory profile**: founded, staff, equipment, certifications, badges, chat response rate, repeat rate, overall service |
| `reviewSummary`, `reviews` | **Buyer reviews**: share of good reviews, grade, counts and top tags of ALL the product's reviews; the reviews read, each with stars, text, date, variant, quantity, photos, masked buyer nickname, level and province |
| `changeType`, `previousPrice`, `priceChangePercent`, `priceHistory` | **Price tracking**: `new`, `price_drop` or `price_rise`; price at the last delivery; change in % (negative = cheaper); `{date, price}` per run that read a price, the last 30 |
| `searchQuery`, `searchLocation`, `position`, `searchUrl`, `scrapedAt` | **Search**: keyword and region of the search, rank in the results (1 = first), results page, ISO timestamp |

Fields of the **Full product page** are empty (`null` or `[]`) when the add-on is off, and so are those of the other add-ons. With **Market statistics per search**, the sheets of figures are in the `MARKET_STATS` record of the run's key-value store (also linked in the Output tab), not in the dataset.

### 💡 Tips

#### How to get more results

Set `maxItems` to `0`, add more keywords (`searchQueries`) and regions (`locations`). 1688 shows at most 2,000 products per search: when you ask for more, the Actor splits the search into price ranges and reads each one. Your sort order is kept inside each price range, not across the whole list, and `position` is then empty; with a sort by price, the ranges are read in that order, so you still get the cheapest (or dearest) products first. The same happens with **Only new products** and a large memory of products already delivered (the search is then read in price ranges even for a small `maxItems`). Chinese keywords give the best results.

#### How to reduce costs

You pay per product and per add-on, so the levers are `maxItems`, `maxItemsPerQuery`, the filters, the add-ons you tick (each one is off by default) and `onlyNew` for recurring runs (you never pay twice for the same product). Prefer the site's own filters (price, MOQ, region, supplier tier, business type, dropshipping, free shipping, 48 h): 1688 applies them before the Actor reads the results, so the products they leave out are never read.

#### Several searches in one run

Fill `searchQueries` and / or `locations`: the Actor runs one search per keyword × region (3 keywords × 4 regions = 12 searches, up to 500 per run). The single `query` and `location` fields still work and are added to the lists. A product found by several searches is saved — and charged — once. Set `maxItemsPerQuery` to give every search its own cap: without it the first searches can use up the whole `maxItems` budget. You can also paste several search URLs into `startUrls`: each one is a search of its own, with the same cap.

#### Monitoring: only the new products

Tick **Only new products** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips the products already delivered: they are not saved, not charged, and their page is not even opened. The memory lives in a named key-value store of your account (`1688-products-scraper-seen`, up to 150,000 products per key) and is only updated with products that really reached the dataset, so a failed run never hides anything. Give each schedule its own `stateKey` (two schedules sharing a key would hide each other's products), and tick `resetState` once to start over. 1688 has no "newest first" order, so each search is read on and stops once 20 results pages in a row hold nothing new.

#### Price tracking

Tick **Also products whose price changed** (`includePriceChanges`) with **Only new products**, and keep the same **Memory key** every run. A product you already received comes back when its price moved by at least `minPriceChangePercent` % since you last received it, with `changeType`, `previousPrice`, `priceChangePercent` and its `priceHistory`. The price followed is `price`, except for a promotional price (`isPromoPrice`: limited-time, after-coupon or after-discount): then it is the regular price, the first price step shown in the search results (none shown: no change can be reported for it that run), so `previousPrice` and `priceChangePercent` are not computed on the `price` of that row.

Only the products found by a search are followed: a product pasted by ID or product URL is delivered once, then skipped like any product already received (the run log says so). The memory keeps the last prices of 50,000 products per key (25,000 when the run has less than 512 MB): past that, the oldest ones are forgotten, and the next price of such a product is learned again without a change being reported.

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run. It returns one item per 1688.com product. Actor id: `nice_dev/1688-products-scraper`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/1688-products-scraper`.

Smallest input, for a cheap first call:

```json
{
    "query": "phone case",
    "maxItems": 10
}
```

Key output fields: `url`, `title`, `price`, `priceTiers`, `minOrderQuantity`, `soldCount`, `supplierName`, `province` and `serviceScores`.

Cost: pay per event, see the pricing section above and the **Pricing** tab. Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

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

The Actor only reads what 1688.com shows publicly to any anonymous visitor. It logs in to nothing. Most of the data is about companies (suppliers and their products), but buyer reviews carry a nickname, masked by 1688, a buyer level and a province: handle personal data in line with GDPR, China's PIPL and the other laws that apply to you, and do not store it without a legitimate reason. You are responsible for using the data in compliance with 1688.com's Terms of Use and applicable law. This Actor is not affiliated with 1688.com or Alibaba Group.

#### Does it need a login or a proxy?

No login and no 1688 account. The proxy is included in the price: leave the default setting (the residential proxy is not available). A request the site turns away is retried at once on a new proxy session, up to 10 times on top of the retries (without a proxy, after a pause of 5 seconds, doubled at each retry up to 150 seconds). If you enter your own proxy URLs in `proxyConfiguration`, they are used as they are: a request they get refused is retried on a new session, up to 10 times on top of the retries, then reported as failed. The Actor never switches to another proxy for you, so check that your proxy can reach 1688.com.

#### Why is the data in Chinese?

The Actor returns what 1688 shows: titles, attributes, supplier names, badges and most reviews are in Chinese, and prices are in Chinese yuan (CNY). Search in Chinese for the best results, or in English. Translate the columns you need with your own tool after the run.

#### Is the data safe to open in Excel or to show on a web page?

Titles and reviews are the sellers' and buyers' own words, copied as they are. A text can begin with `-`, `+`, `=` or `@`: Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. On a web page, escape every field like any text written by a stranger.

#### Known limitations

- 1688 shows at most 2,000 products per search. Above that, the search is split into price ranges: every product is still saved once, but the global order is not kept across the ranges and `position` is empty (this also happens, below 2,000 products asked for, with **Only new products** and a large memory).
- Site filters that are not in the input can still be used by pasting a filtered search URL into `startUrls`.
- Photos beyond the main one, video, attributes, variants, stock, weight, shipping origin and delivery days come from the product page: they are empty when **Full product page** is off.
- `isSuperFactory` is only known when the search was restricted to super factories (`merchantType`): 1688 does not flag it on the result. `isVerifiedMerchant` is also true when 1688 flags the product; otherwise both are `null`.
- `reviewSummary` is given when 1688 returns it: it can be `null` while the reviews themselves are there.
- `onlyNew` remembers product IDs, not their content: a product whose price changed comes back only with **Also products whose price changed**.
- Two runs sharing the same `stateKey` at the same time may both return the same new product.

**A run that reaches its timeout** stops itself about 45 seconds before it: no new page is asked, what it read is saved and, with `onlyNew`, remembered, and the run ends *Succeeded* with "Stopped before the run's timeout". Resurrect it to go on from there, or give the next run a longer timeout (Run options).

**A run the platform stops without warning** (out of memory)

- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the products already saved are skipped: none is delivered or charged twice, and `maxItems` still counts them.
- With `onlyNew`, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the products it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the products of its last 2 seconds once more.

#### Something doesn't work?

The last line of the log counts the products saved, filtered out and no longer on 1688.com (removed while the run was reading them), and the requests that failed after every retry. Those requests and the removed products are listed, with the reason, in the `FAILED_REQUESTS` record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause.

If 1688.com changes its pages, you are told instead of paying for blank rows. A results page that counts products but gives none the Actor can read is an error (listed in `FAILED_REQUESTS`), never a quiet "No products found". If the first 20 products read all lack their title, price, main photo, supplier details or another field 1688 gives on every product, the run saves nothing more, stops and fails, and its last message names the missing field: at most those first products are charged. A run of fewer products (a scheduled `onlyNew` run that finds a few new ones, a small **Max products**) is checked at its end, from 5 products: its products are already saved, and the run fails with the missing field instead of ending green.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which URLs failed and why.

# Actor input Schema

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

1688 search URLs (`https://s.1688.com/selloffer/offer_search.htm?keywords=...`, the keyword and supported filters are read from the URL, pagination is automatic) or product URLs (`https://detail.1688.com/offer/<id>.html`, `https://m.1688.com/offer/<id>.html`). A product URL is read from its product page, so the **Full product page** price applies, as for Offer IDs. When this list is not empty, the search fields below are ignored. The sort order and the supplier filters of the form (supplier label, business type, dropshipping, free shipping, 48 hours, one per supplier) are added to a search URL that does not already carry them; a filter already in the URL wins. The other filters, caps and monitoring apply to every product. Max 1 000 URLs.

## `query` (type: `string`):

Product to search, in Chinese (best results, e.g. `手机壳`) or English (e.g. `phone case`).

## `searchQueries` (type: `array`):

Several keywords in one run: one search per keyword (times each supplier region below). Added to **Search keyword**; products found by several searches are saved once.

## `offerIds` (type: `array`):

1688 product IDs to read directly (the number in `detail.1688.com/offer/<id>.html`). Each ID opens its product page, so the **Full product page** price applies. Can be combined with keywords; to read only these IDs, empty **Search keyword** (the form pre-fills one).

## `location` (type: `string`):

Supplier province or city, in Chinese, as on 1688 (e.g. `广东` Guangdong, `浙江` Zhejiang, `深圳` Shenzhen, `东莞` Dongguan). A city is searched inside its province. Empty = all of China.

## `locations` (type: `array`):

Several provinces or cities in one run: every keyword is searched in every region (3 keywords × 4 regions = 12 searches, max 500). Added to **Supplier region**.

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

Maximum number of products to save for the whole run (after deduplication and filters). 0 = no limit. 1688 shows at most 2 000 products per search: above that, the Actor splits the search into price bands by itself.

## `maxItemsPerQuery` (type: `integer`):

Cap for EACH search (keyword × region, or search URL), so that the first search cannot use up the whole **Max products** budget. 0 = no per-search cap.

## `sortBy` (type: `string`):

Order of the 1688 results.

## `priceMin` (type: `number`):

Only products whose unit price is at least this, in Chinese yuan. Empty = no minimum.

## `priceMax` (type: `number`):

Only products whose unit price is at most this, in Chinese yuan. Empty = no maximum.

## `minOrderQuantity` (type: `integer`):

Only products whose minimum order quantity is at most this many units (find suppliers that sell small quantities). Empty = no limit.

## `merchantType` (type: `string`):

1688 supplier label.

## `businessType` (type: `string`):

Kind of company that sells the product.

## `dropshipOnly` (type: `boolean`):

Only products the supplier ships one by one to your customers.

## `freeShippingOnly` (type: `boolean`):

Only products with free shipping inside China.

## `ships48hOnly` (type: `boolean`):

Only products the supplier promises to ship within 48 hours.

## `onePerSupplier` (type: `boolean`):

Keep 1688's best match per supplier: more different suppliers in the same number of results. Above 2,000 products a search is read in price ranges: one product per supplier in each range.

## `extractDetails` (type: `boolean`):

Open each product page for the full photo gallery, video, all attributes (material, size, model...), stock, MOQ, shipping origin and delivery promise, after-sales services and description link. Charged per product read this way (see Pricing). Off = search-result fields only.

## `includeSupplierDetails` (type: `boolean`):

Add the supplier's factory profile: founding date, staff, production equipment, certifications, ranking badges, chat response rate and repeat-buyer rate. Read once per supplier and charged per supplier profile (see Pricing).

## `includeMarketStats` (type: `boolean`):

Adds one sheet of figures per search: products and suppliers, lowest, median, highest and average price, median minimum order, share of factories, share of verified suppliers, top 10 provinces, units sold and share of paid ads. One sheet per search, price ranges merged. Worked out from the products this run delivers (with Only new products, the new ones only). Find it in Storage → Key-value store → `MARKET_STATS`, or in the Output tab. Charged per sheet delivered (see Pricing).

## `includeReviews` (type: `boolean`):

Add each product's buyer reviews to its row (`reviews`): stars, text, date, variant and quantity bought, photos, buyer nickname, level and province, plus a summary of the ratings (`reviewSummary`: positive rate, grade, counts by type, top tags). The reviews are inside the product row, not rows of their own. Charged per review delivered (event `review`).

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

Reviews kept per product, in 1688's default order. Read 10 at a time.

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

1688's own review filter: every review, only those with photos, or only the good, medium or bad ones (the buyer's rating).

## `reviewMinRating` (type: `integer`):

Keep only the reviews with at least this many stars (1-5). Empty = all.

## `reviewMaxRating` (type: `integer`):

Keep only the reviews with at most this many stars, e.g. 2 for the complaints. Empty = all.

## `reviewKeyword` (type: `string`):

Keep only the reviews whose text contains this word or phrase (case and accents ignored), e.g. `质量` or `broke`. 1688 cannot filter reviews by text, so the Actor reads more pages to find enough of them. Empty = all.

## `reviewPostedAfter` (type: `string`):

Keep only the reviews written on or after this date: `2026-03-01`, or a period before now such as `30 days`, `3 months`. Reviews without a readable date are dropped. Empty = all.

## `excludeKeywords` (type: `array`):

Drop the products whose title contains one of these words (case and accents ignored).

## `minRating` (type: `number`):

Only suppliers whose overall 1688 service score (0-5) is at least this. Products of a search without a score are dropped; a product pasted by ID or URL is not checked (the score comes from the search results).

## `verifiedOnly` (type: `boolean`):

Only suppliers whose factory was inspected on site (深度验厂 / 实地验厂). Read from the search results: a product pasted by ID or URL is not checked.

## `excludeAds` (type: `boolean`):

Drop the paid placements 1688 mixes into the results (they are kept and flagged `isAd` otherwise).

## `onlyNew` (type: `boolean`):

Skip the products that a previous run (same **Memory key**) already delivered: they are not saved and not charged, and their page is not even opened. First run = everything is new.

## `stateKey` (type: `string`):

Name of the memory used by **Only new products**. Give each schedule / task its own key (e.g. `phone-cases-guangdong`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every product again. Untick it afterwards.

## `includePriceChanges` (type: `boolean`):

Also return a product you already received when its price went up or down since your last run, with the previous price, the change in % and the price history. The price followed is the first price step shown on the search card. Needs **Only new products** and the same **Memory key** every run. You pay for each product that comes back. Products pasted by ID or URL are not followed.

## `minPriceChangePercent` (type: `number`):

A product comes back only if its price moved by at least this many % since the last time you received it. 0 = every change.

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

Apify Proxy or your own proxies. Keep the default: it is included in the price. The residential Apify proxy is not available in this Actor.

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

Maximum number of requests processed in parallel.

## `maxRequestsPerMinute` (type: `integer`):

Most requests to the site in any 60 seconds, all of them counted: results pages, product pages and supplier profiles. A budget, not an even pace: up to this many can leave at once when the minute starts (spread them with the minimum delay below). Lower it if the log shows many refused requests.

## `minRequestIntervalMs` (type: `integer`):

Smallest gap between two requests, in milliseconds. Unlike the per-minute rate, this spreads the requests evenly instead of letting them go out in a burst. 0 = no gap.

## `maxRequestRetries` (type: `integer`):

Retries per request before it is marked as failed. Behind a proxy, a request the site turns away is also retried on a new proxy session up to 10 times without using up these retries.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "startUrls": [],
  "query": "手机壳",
  "searchQueries": [],
  "offerIds": [],
  "locations": [],
  "maxItems": 100,
  "maxItemsPerQuery": 0,
  "sortBy": "relevance",
  "merchantType": "any",
  "businessType": "any",
  "dropshipOnly": false,
  "freeShippingOnly": false,
  "ships48hOnly": false,
  "onePerSupplier": false,
  "extractDetails": false,
  "includeSupplierDetails": false,
  "includeMarketStats": false,
  "includeReviews": false,
  "maxReviewsPerProduct": 20,
  "reviewFilter": "all",
  "excludeKeywords": [],
  "verifiedOnly": false,
  "excludeAds": false,
  "onlyNew": false,
  "stateKey": "default",
  "resetState": false,
  "includePriceChanges": false,
  "minPriceChangePercent": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 8,
  "maxRequestsPerMinute": 120,
  "minRequestIntervalMs": 0,
  "maxRequestRetries": 5,
  "debugLog": false
}
```

# Actor output Schema

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

No description

## `marketStats` (type: `string`):

No description

# 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 = {
    "query": "手机壳",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nice_dev/1688-products-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 = {
    "query": "手机壳",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("nice_dev/1688-products-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 '{
  "query": "手机壳",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call nice_dev/1688-products-scraper --silent --output-dataset

```

## MCP server setup

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