1688 Products Scraper
Find factory suppliers and wholesale prices for a product idea, compare them with your retail price, or watch a supplier's offers. Type a keyword in Chinese or English, or paste 1688 offer links or ids, and get wholesale products from 1688.com as one JSON row per product: price tiers by quantity, minimum order, units sold, repurchase rate, supplier and factory data. $1.80 per 1,000 products on the free plan, and you pay only for the rows you get.
$1.80 per 1,000 product (search result)s on the Free plan, down to $1.35 on higher plans
Why this actor
- Search and detail in one actor, 10% under each. A search row costs $1.80 per 1,000 against devcake's $2; a row with details $4.49 against zen-studio's $4.99 per product (free plan, Apify Store, 2026-10-31).
- Price tiers, MOQ and supplier scores in the search row: price per quantity step, minimum order, units sold, repurchase rate, factory flag and supplier service scores, without opening each product page.
- Seller login names and tracking data are dropped; contact details found in text are redacted. Free error rows with a machine-readable
code(not_found,blocked,unavailable...), so an agent knows whether to retry.
Drop-in input
Drop-in input. Input written for zen-studio/1688-wholesale-scraper (keywords, offerIds, maxResults, sortBy, priceMin, priceMax, includeSkuDetails) or devcake/1688-com-products-scraper (queries, maxProducts, sortType) works as it is.
As stated in the actor’s README. The full list of accepted input names is on the Store page.
Switching from another actor
- From 1688 Wholesale Products Scraper zen-studio/1688-wholesale-scraper, 7 input fields work as they are
What you get
| Field | What it holds |
|---|---|
offerId, url, title | The offer id (the number in the product link), its link and its title as the seller wrote it (Chinese). |
keyword, rank, isAd | The search keyword and the position in the results (paid placements included), and whether the row is a paid placement. Empty for id and link lookups. |
priceMin, priceMax, priceTiers | Prices in Chinese yuan (CNY). priceTiers lists the wholesale steps: { minQty, maxQty, price }. |
moq, unit | Minimum order quantity and the selling unit (个, 件, 套). |
soldCount, soldText, soldScope | Units sold as a number and as the site shows it (已售500+件). soldScope is offer for this listing and network for the "全网" figure of the whole product. With details, soldCount is the exact total. |
bookedCount, repurchaseRate | Number of orders on the search card, and the share of buyers who reordered this offer (0-100). |
images, videoUrl, category | Image links, the main video and the category (id, and name with details). |
origin | Province and city of the dispatch location. |
serviceTags | Service badges such as 先采后付 (buy now, pay later), 深度验厂 (inspected factory), 退货包运费. |
supplier | companyName, memberId, isFactory, isSuperFactory, factoryInspected, yearsOnPlatform, serviceScores (0-5: composite, consultation, logistics, dispute, returns, goods), repurchaseRate3m, shopUrl. |
skus | With details: every variant as { skuId, attrs, price, stock, sold }. |
attributes | With details: the product parameters (material, brand, model, ...) as { name, value }. |
freight | With details: dispatch promise (text), shipsFrom, free and an indicative fee. |
rating | With details: score, goodRatePct and reviewCount of buyer reviews. |
hasDetails | true when the row carries the detail fields. |
Sample row (from the README example; long text shortened, lists cut to two items):
{
"rowType": "product",
"platform": "1688",
"offerId": "866095761513",
"url": "https://detail.1688.com/offer/866095761513.html",
"title": "数据线保护套硅胶防折断充电线保护套咬线器防断裂神器",
"keyword": "数据线",
"rank": 2,
"isAd": false,
"currency": "CNY",
"priceMin": 2.5,
"priceMax": 2.6,
"priceTiers": [
{
"minQty": 3,
"maxQty": 4999,
"price": 2.6
},
{
"minQty": 5000,
"maxQty": 99999,
"price": 2.55
}
],
"moq": 3,
"unit": "件",
"soldCount": 100000,
"soldText": "已售10万+件",
"soldScope": "offer",
"repurchaseRate": 17,
"origin": {
"province": "广东",
"city": "东莞市"
},
"supplier": {
"companyName": "东莞市元拓橡塑制品有限公司",
"memberId": "b2b-22072902285003c713",
"isFactory": true,
"yearsOnPlatform": 7,
"serviceScores": {
"composite": 4,
"consultation": 4,
"logistics": 3.57,
"dispute": 5,
"returns": 3.67,
"goods": 3.33
},
"repurchaseRate3m": 77,
"shopUrl": "https://apetop.1688.com"
},
"hasDetails": false
}
Price
Live Apify price on 2026-11-01, per 1,000 rows, by Apify plan. You pay only for rows delivered; error and summary rows marked free in the README cost nothing. Plus $0.001 per GB of memory when a run starts.
| Per 1,000 | Free | Bronze | Silver | Gold | Platinum | Diamond |
|---|---|---|---|---|---|---|
| Product (search result) (main) | $1.80 | $1.80 | $1.62 | $1.35 | $1.35 | $1.35 |
| Product with details | $4.49 | $4.31 | $4.04 | $3.59 | $3.59 | $3.59 |
Use cases
- Sourcing: find factories for a product and compare price tiers, minimum orders and repurchase rates.
- Price tracking: run weekly on a fixed keyword list and compare
priceTiersandsoldCountover time. - Margin check: take the first price tier and the minimum order into your landed-cost calculator.
- Category research: sort by sales and read what moves, at which price.
Run it from code or an AI agent
Actor ID arcadium/1688-products. Set APIFY_TOKEN to your Apify API token. The input below is the actor’s prefilled example; see the guide for every field.
curl
curl -X POST "https://api.apify.com/v2/acts/arcadium~1688-products/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"keywords":["保温杯"],"maxItemsPerKeyword":50,"sort":"relevance","includeDetails":false}'JavaScript
// npm install apify-client
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('arcadium/1688-products').call({
"keywords": [
"保温杯"
],
"maxItemsPerKeyword": 50,
"sort": "relevance",
"includeDetails": false
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);Python
# pip install apify-client
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("arcadium/1688-products").call(run_input={
"keywords": ["保温杯"],
"maxItemsPerKeyword": 50,
"sort": "relevance",
"includeDetails": False,
})
items = client.dataset(run.default_dataset_id).list_items().items # apify-client 3.x returns a Run object
print(items)MCP
{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=arcadium/1688-products",
"headers": {
"Authorization": "Bearer <APIFY_TOKEN>"
}
}
}
}LangChain
# pip install langchain-apify (reads APIFY_API_TOKEN from the environment)
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("arcadium/1688-products")
rows = tool.invoke({"run_input": {
"keywords": ["保温杯"],
"maxItemsPerKeyword": 50,
"sort": "relevance",
"includeDetails": False,
}})
# or give `tool` to an agent: create_react_agent(llm, [tool])LlamaIndex
# pip install llama-index-readers-apify
import os
from llama_index.core import Document, VectorStoreIndex
from llama_index.readers.apify import ApifyActor
reader = ApifyActor(os.environ["APIFY_TOKEN"])
documents = reader.load_data(
actor_id="arcadium/1688-products",
run_input={
"keywords": ["保温杯"],
"maxItemsPerKeyword": 50,
"sort": "relevance",
"includeDetails": False,
},
dataset_mapping_function=lambda item: Document(text=str(item.get("title") or ""), metadata={"url": item.get("url")}),
)
index = VectorStoreIndex.from_documents(documents)CrewAI
# pip install crewai crewai-tools langchain-apify (reads APIFY_API_TOKEN from the environment)
from crewai import Agent
from crewai_tools import ApifyActorsTool
tool = ApifyActorsTool(actor_name="arcadium/1688-products")
researcher = Agent(
role="Research analyst",
goal="Answer with data collected by the tool",
backstory="Uses public web data.",
tools=[tool],
)n8n
{
"nodes": [
{
"name": "Run arcadium/1688-products",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
0,
0
],
"parameters": {
"method": "POST",
"url": "https://api.apify.com/v2/acts/arcadium~1688-products/run-sync-get-dataset-items",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "{\"keywords\":[\"保温杯\"],\"maxItemsPerKeyword\":50,\"sort\":\"relevance\",\"includeDetails\":false}",
"options": {
"timeout": 300000
}
}
}
],
"connections": {}
}Google Sheets
// Extensions > Apps Script. Store your token once: Project Settings > Script properties > APIFY_TOKEN.
function importLastRun() {
const token = PropertiesService.getScriptProperties().getProperty('APIFY_TOKEN');
const url = 'https://api.apify.com/v2/acts/arcadium~1688-products/runs/last/dataset/items?status=SUCCEEDED&clean=true&format=json';
const res = UrlFetchApp.fetch(url, { headers: { Authorization: 'Bearer ' + token } });
const rows = JSON.parse(res.getContentText());
if (!rows.length) return;
const keys = Object.keys(rows[0]);
const values = rows.map((r) => keys.map((k) => (typeof r[k] === 'object' ? JSON.stringify(r[k]) : r[k])));
const sheet = SpreadsheetApp.getActiveSheet();
sheet.clearContents();
sheet.getRange(1, 1, 1, keys.length).setValues([keys]);
sheet.getRange(2, 1, values.length, keys.length).setValues(values);
}Tutorials
Limitations
- Public data only. Nothing behind a login, and no contact details of sellers.
- 1688 shows at most 2,000 results per search. Use several keywords or price bands to go deeper.
- Prices are in yuan and titles, attributes and tags are in Chinese. Translation is not included.
- 1688 sometimes answers a search without the product list. The actor retries; if it still fails you get a free
blockedrow. - 1688 sometimes refuses all searches for a few minutes. The actor then waits up to
searchGateWaitMinutes(default 12, tries again every 3 minutes, nothing is charged while it waits) and carries on once searches work again. If they still fail, every keyword it could not search gets a freeblockedrow: run it again later. SetsearchGateWaitMinutesto 0 to stop at once instead. Product pages work the same way: if they keep refusing, the remaining keyword results arrive as plain products, charged at the plain price. - A search row has no variants. Add details for
skus. soldCountof a search row is a lower bound ("500+"). With details it is the exact total of the listing. The "全网" figure (soldScope: network) covers the same product across the web, not only this listing.- The freight
feeis indicative; 1688 calculates the real freight from the destination. - Titles and attributes are cleaned of e-mail addresses, phone numbers and messenger handles; a seller can still hide contact data in an image.
FAQ
Can I search in English? Yes. 1688 translates English keywords itself ("water bottle" returns water cups and bottles), but Chinese keywords usually match more precisely.
Why does a product have no priceTiers? The seller prices each variant on its own. Read priceMin, priceMax and skus[].price.
Why is soldCount the same for many products? Search rows show a lower bound such as 500+ or 10万+. Use details for the exact number.
Something looks wrong in the output. Who do I tell? Open an issue on the actor page with the run link. We read them all.
Related actors
Amazon Product & Best Sellers Scraper
Amazon product search, Best Sellers ranks and Buy Box offers on 21 stores, $0.54 per 1,000 search rows vs $1 at the two most used search actors.
$0.54 per 1,000 search results
Etsy Scraper
Etsy product research: full listings for keywords or URLs, $7.20 per 1,000, 10% under the most used Etsy scraper's $8, whose input works as is.
$7.20 per 1,000 listings on the Free plan, down to $5.40 on higher plans