# Alibaba Scraper: Products, Prices, MOQ, Suppliers (`automation_craft/alibaba-scraper`) Actor

Scrape Alibaba.com offers by keyword, search link, category or product link, no login. Get the USD price per unit at the minimum order, the quantity price ladder, MOQ, supplier country, Verified and Trade Assurance badges, and a median price row per search. JSON, CSV, Excel or API; pay per offer.

- **URL**: https://apify.com/automation_craft/alibaba-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** E-commerce, Lead generation, Developer tools
- **Security:** Limited permissions
- **Stats:** 5 total users, 4 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 offers

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

### Alibaba Scraper: Products, Prices, MOQ, Suppliers

**Alibaba scraper for product offers with the real price at the minimum order**: search Alibaba.com by keyword, search link,
category or product link and get one row per offer with the USD price per unit at the minimum order quantity (MOQ), the
quantity price ladder, MOQ and unit, a per piece flag, and the supplier's facts (country, years on Alibaba, Verified, Verified
Pro, Trade Assurance, business type, response rate, store rating). Every search adds one price summary row with the median
and quartiles of that price. No login, no cookies, no browser.

It is built for Amazon private label and FBA sellers sizing a product idea, sourcing agents building supplier shortlists,
product and market researchers comparing factory prices across keywords, and apps and AI agents that need a typical
wholesale price for a product in one call.

#### What it does

- **The price at the minimum order, not the bulk price**: `unitPriceAtMoq` is the ladder tier that holds the MOQ. The low end
  of an offer's range (`priceMin`) is the price at the largest order and is kept apart.
- **The price at your quantity**: give `orderQuantity` and every row adds `unitPriceAtQuantity` from the offer's own ladder.
- **A clean unit on every row**: `priceUnit` (piece, set, pair, meter, kilogram and 17 more), `isPerPiece` and `unitClass`, so
  a price per meter never mixes with a price per piece.
- **A price summary per search**: a headline median and quartiles of the price at MOQ (`medianUsd`: offers whose title holds
  every keyword word, else the first offers Alibaba ranks best inside your price range), and beside it the median, quartiles, minimum and maximum per piece and per
  sellable item, over the offers delivered.
- **Alibaba's own filters, checked again on every row**: price, MOQ, supplier country, Verified, Verified Pro, Ready to Ship,
  certifications, store rating, plus filters applied on the row: Trade Assurance, business type (manufacturer and four more),
  years on Alibaba, lead time, ads, title match and ids to leave out. A row that fails a filter is left out, free.
- **Pasted links**: Alibaba search, catalog and product links, read with their own filters.
- **Product details on request**: attributes, variants and their prices, customisation, sample price, lead times, packaging,
  places of dispatch and certifications with validity.
- **A search that matches nothing is free**: Alibaba answers every word, nonsense included, with 48 offers. A search whose
  first page holds no offer whose title carries the keyword delivers one free `no_match` row and no billed offer.

### Quick start

1. Open the Actor and type one or more keywords as you would on Alibaba.com, for example `yoga mat` or `steam cleaner
   handheld`.
2. Set `maxResultsPerKeyword` (20 by default, up to 960) and add filters if you want: a price range, a largest MOQ, supplier
   countries, Verified suppliers only.
3. Turn on `orderQuantity` if you plan a given order size, and `includeDetails` if you need the product page facts.
4. Run it, then download the dataset as JSON, CSV or Excel, or read it through the API.

The prefilled input searches `yoga mat` and delivers 20 offers and one price summary row in a few seconds.

### What you get

One row per offer (`type: "offer"`), and per search one price summary row (`type: "keywordSummary"`) and one coverage row
(`type: "search"`: pages read, offers seen and delivered, repeats, rows left out by reason, why the walk ended). A product link
gives one `type: "product"` row. Status rows (`type: "status"`) name anything not delivered (an input problem, a product
Alibaba no longer shows, a search with no match, a stop), and the run summary (`type: "summary"`) comes last. Only offer and
product rows are billed as rows; the summary, coverage and status rows are free.

Fill rates are measured over 10,560 offers of 11 keywords read on pages 1 to 20 (2026-11-04); the
`unitPriceAtMoq` figure is from 200 offers of 10 keywords checked against their product pages:

| Field | What it holds | Example (platform run, `yoga mat`) | Filled |
|---|---|---|---|
| `offerId`, `title`, `url`, `imageUrl` | the offer | `1601799200051` | 100% |
| `unitPriceAtMoq` | USD price per unit at the minimum order | `5.12` | 76% (the rest price by variant or state no single price) |
| `priceBasis` | `quantity_ladder`, `single_price`, `price_range` or `not_stated` | `quantity_ladder` | 100% |
| `priceTiers` | the quantity ladder: `minQuantity`, `maxQuantity`, `priceUsd`, `promotionPriceUsd` | `20 to 499: 5.12`, `500+: 4.72` | 67.9% (offers with 2 or more tiers; a one tier offer shows its single price in `unitPriceAtMoq`) |
| `priceMin`, `priceMax` | the offer's USD range; `priceMin` is the price at the largest order | `4.72`, `5.12` | 100% |
| `priceText` | Alibaba's own price text | `US $4.72-$5.12` | 100% (in US $ 99.8%) |
| `moq`, `moqUnit`, `moqText` | the minimum order as a number, its unit and Alibaba's text | `20`, `piece`, `20 pieces` | 100% |
| `priceUnit`, `isPerPiece`, `unitClass` | the normalised unit; true for piece or unit; item, length, area, weight, volume, pack or other | `piece`, `true`, `item` | 100% (per piece on 66.0%) |
| `leadTimeDays` | the lead time on the search card | `7` | 100% |
| `leafCategoryId`, `leafCategoryName` | Alibaba's category | `Yoga Mats` | 100% |
| `supplier.name`, `supplier.id`, `supplier.country`, `supplier.years` | the supplier | `CN`, `1` | 100% |
| `supplier.verified`, `supplier.verifiedPro`, `supplier.goldSupplier` | Alibaba's badges | `false`, `false`, `true` | 100% |
| `supplier.tradeAssurance` | takes Trade Assurance orders | `true` | true on 98.7% |
| `supplier.businessTypes` | manufacturer, trading_company, distributor, buying_office, other | `["trading_company"]` | 98.6% |
| `supplier.responseRate` | response rate in percent | `84.4` | 99.3% |
| `supplier.rating`, `supplier.reviewCount` | store rating out of 5 and review count | `4.8`, `2` | 74.6% |
| `unitsSold`, `views` | sold and view counts where Alibaba shows them | `null` | 23.3%, 4.7% |
| `isAd` | a paid placement | `false` | true on 14.4% |
| `titleMatchesKeyword`, `titleMatchShare` | the title holds at least half the keyword's words | `true`, `1` | 100% (the share is empty on category browses) |

Also on the row: `images`, `hasVideo`, `promotion`, `deliveryEstimate`, `shippingCostText`, `readyToShip`, `easyReturn`,
`productCertifications`, `attributes`, `supplier.inspectedBy`, `supplier.companyCertifications`, `supplier.staff`,
`supplier.exportCountries`, `supplier.storeUrl`, `keyword`, `page`, `position`, `sortedBy` and `scrapedAt`. With
`includeDetails`, a `details` object adds `categoryPath`, `attributes`, `variants`, `variantPrices`, `customization`,
`sample`, `leadTimes`, `packaging`, `shipsFrom`, `certifications` and the page's `supplier` facts.

#### How to read the price fields

- `unitPriceAtMoq` is the price you pay per unit when you order the minimum. On 76 of 76 laddered or single priced offers
  checked, it equals the product page's price at the MOQ.
- `priceBasis: "price_range"` means the price depends on the variant (colour, size, capacity): `unitPriceAtMoq` stays empty
  and `unitPriceAtMoqMin` and `unitPriceAtMoqMax` give the range. A single figure there would be a guess.
- `isPerPiece` is true only for pieces and units. Sets, pairs and bags are items too (`unitClass: "item"`); meters, kilograms
  and cartons are not.
- `placeholderSuspected` marks an MOQ of 100,000 or more, or a price of USD 0.01 or less, which suppliers often use as
  placeholders.
- `outOfRange` (with a price range set) is true when the price at MOQ lies outside your range.

#### The price summary row

One `keywordSummary` row per search, in USD per unit at the minimum order, over the offers this run delivered for that search
(ads included unless `excludeAds`).

**The headline is `medianUsd`**, with `lowerQuartileUsd`, `upperQuartileUsd`, `pricedOffers` and `headlineFigure` naming where
it comes from: the median price at MOQ of offers priced per item (pieces, units, sets, pairs and bags each as one sellable
item) whose title holds every word of the keyword (`perItemAllWords`) when there are 5 or more of them; otherwise the first
offers figure (`firstOffers`): the median price at MOQ of the first 10 offers priced per item in Alibaba's best match order
(`summaryOffers` sets 5 to 50), counting only offers inside your price range, a variant priced offer at the low end of its
range. With fewer than 5 of either, the headline stays empty and `headlineNote` says why. Beside it, unchanged: `perPiece`
(per piece rows whose title carries at least half the keyword), `perItem` (the same over item units), `perItemAllWords`,
`firstOffers`, `byUnit` and `perPieceAllTitles`. Variant priced rows, placeholders and rows outside your price range stay out
of the other figures, counted in `leftOutOfFigures`.

**How to get a typical factory price for a product idea:** search the words a buyer would type and give a price range
around the price you expect (`minPrice`, `maxPrice`, wide: for example a tenth to four times it). The range keeps accessories,
spare parts and bulk listings out of every figure. The headline then reads, at the minimum order, the offers whose title
holds every word of your keyword when there are 5 or more of them, else the first offers Alibaba ranks best inside your range.

How close it gets, measured honestly: on 9 product ideas checked by hand against product pages (saved answers, no range),
the headline landed within 15 percent of the hand checked price at MOQ on 7 of 9 (8 of 9 against every relevant offer of the
first 20). On 6 longer product ideas with known supplier prices and a price range each (real runs, 2026-11-06), it landed
within 15 percent on 2 of 6, with a median error of 20 percent: long keywords rarely have 5 titles holding every word, so
the first offers figure carries them, and a product sold mostly as a set or with accessories misses by about half. The low
end of offers' ranges (the bulk price) missed by up to 60 percent.

Summary row of the prefilled search (`yoga mat`, 20 offers, read 2026-11-06, trimmed):

```json
{
  "type": "keywordSummary",
  "keyword": "yoga mat",
  "currency": "USD",
  "headlineFigure": "perItemAllWords",
  "medianUsd": 7.84,
  "lowerQuartileUsd": 3.9925,
  "upperQuartileUsd": 13.725,
  "pricedOffers": 14,
  "headlineNote": null,
  "offersDelivered": 20,
  "perPieceOffers": 19,
  "adsCounted": 10,
  "perItemAllWords": { "count": 14, "median": 7.84, "lowerQuartile": 3.9925, "upperQuartile": 13.725, "min": 2.9, "max": 408 },
  "firstOffers": { "count": 10, "median": 4, "lowerQuartile": 3.715, "upperQuartile": 8.915, "min": 2.8, "max": 14.5, "firstN": 10 },
  "perItem": { "count": 14, "median": 7.84, "lowerQuartile": 3.9925, "upperQuartile": 13.725, "min": 2.9, "max": 408 },
  "perPiece": { "count": 14, "median": 7.84, "lowerQuartile": 3.9925, "upperQuartile": 13.725, "min": 2.9, "max": 408 },
  "complete": false,
  "stoppedBy": "maxResultsPerKeyword"
}
```

### How much does it cost to scrape Alibaba?

You pay per event (Apify's pay per event model): per offer row delivered, once per search that delivered offers, and for the
extras you turn on. Prices per 1,000 events by Apify plan:

| Event | What it is | Free | Bronze | Silver | Gold |
|---|---|---|---|---|---|
| Offer | one offer row | $0.69 | $0.63 | $0.57 | $0.49 |
| Search | one search (a keyword, link or category, per supplier country) that delivered at least one billed offer, with its price summary row | $1.40 | $1.28 | $1.16 | $1.00 |
| Product detail | one product page read and delivered (`includeDetails`, or a product link) | $2.66 | $2.43 | $2.20 | $1.90 |
| Delivery country | once per run that reads as a buyer in a chosen country (`shipToCountry` or a residential proxy) | $28.00 | $25.60 | $23.20 | $20.00 |

Platinum and Diamond plans pay the Gold price. The Actor start event is $0.0075 per run at the default 256 MB, at every
plan (Apify charges it per GB of the run's memory). The Store pricing card shows these same prices per 1,000 events:
"$0.49 / 1,000" on the Offer row means one offer costs 0.049 cents at Gold, and "$20.00 / 1,000" on the Delivery country row
means one delivery country costs 2 cents at Gold.

Worked example on the Gold plan: one keyword with 20 offers (the prefilled run) costs $0.0075 start fee + 20 x $0.00049 +
1 x $0.001 = $0.0183. On the Bronze plan, 10 keywords of 100 offers each cost $0.0075 + 1,000 x $0.00063 + 10 x $0.00128 =
about $0.65; with `includeDetails` add 1,000 x $0.00243 = $2.43.

Never billed: repeats of an offer already delivered in the run, offers your filters or excluded ids leave out, ads left out,
a search that matches nothing, product pages that cannot be read, and the coverage, summary and status rows. A run refused
for its input reads nothing from Alibaba. Only the run's start fee is charged. `maxItems` (1,000 by default) caps the paid
rows of a run, and a row whose events do not fit your run's charge limit is held back, not delivered unpaid. Work that bills
nothing has an allowance: a run whose searches match nothing stops after about 30 such searches at 256 MB (about 9 at 1 GB),
with a free row that says so, and the searches after that point are not read. A run also holds at most 2,500 offers it has
read but not yet delivered (many sorted or paused searches at once); past that, the newest are dropped, not charged, and a
free row and the coverage row say so. Product pages (`includeDetails`, product
links) are read one at a time about 6 seconds apart, about 500 to 600 an hour: a run that needs more than that needs a
timeout above the default hour.

### Input

At least one of `keywords`, `searchUrls`, `productUrls` or `categoryIds`. Every setting is described in the input schema;
"Alibaba's filter" means it is sent to Alibaba, "on each row" means every delivered row is checked, and rows that fail are
left out, free, and counted by reason on the coverage row.

#### What to search

| Setting | What it does |
|---|---|
| `keywords` | product words, one search each; duplicates are read once; a pasted Alibaba link is read as a link |
| `searchUrls` | `trade/search`, `search/page` or `catalog/<name>_cid<id>` links, and showroom links (`products/<words>.html`, read as a search of their words, which the coverage row says); their words, category, page and filters apply, and a setting you give replaces the link's own; a link with a parameter this Actor does not read is refused with a free row naming it |
| `productUrls` | product links or ids, each read from its product page and billed as one Product detail |
| `categoryIds` | with keywords, each keyword is searched in each category; alone, each category is browsed (Alibaba's filter; the category is judged by Alibaba only) |

A run takes at most 200 searches (keywords x categories x supplier countries, plus links) and 1,000 product links.

#### How many and in what order

| Setting | What it does |
|---|---|
| `maxResultsPerKeyword` | offers per search, 1 to 960 (default 20); Alibaba serves one search 20 pages of 48 offers |
| `maxPagesPerKeyword` | result pages per search, 1 to 20 (default 20 in Alibaba's orders, 1 with an in-run sort) |
| `summaryOffers` | how many first offers the summary row's first offers figure counts, 5 to 50 (10 when left out) |
| `startPage` | the page each search starts at, 1 to 20 |
| `maxItems` | paid rows of the whole run, 1 to 100,000 (default 1,000) |
| `sortBy` | `best_match` (default) and `sales` are Alibaba's own orders; `price_low`, `price_high` and `response_rate` are **in-run sorts**: Alibaba serves no such order, so the Actor sorts the offers it read and each row's `sortedBy` says so |

#### Price and order quantity

| Setting | What it does |
|---|---|
| `minPrice`, `maxPrice` | Alibaba's price filter in USD per unit; each row gets `outOfRange`, and a row whose whole range misses yours, or that states no price, is left out |
| `maxMoq` | Alibaba's filter, and on each row: only offers you can order in this quantity or less |
| `minMoq` | on each row: only offers whose MOQ is at least this |
| `orderQuantity` | adds `unitPriceAtQuantity` from each offer's ladder (empty, with `belowMoq: true`, below the offer's MOQ) |

#### Supplier

| Setting | What it does |
|---|---|
| `supplierCountries` | Alibaba's country filter, one search per country, and on each row (up to 20 countries) |
| `verifiedOnly`, `verifiedProOnly` | Alibaba's Verified and Verified Pro filters, and on each row |
| `tradeAssuranceOnly` | on each row |
| `businessTypes` | on each row: manufacturer, trading_company, distributor, buying_office, other (with `verifiedOnly`, manufacturer gives verified manufacturers) |
| `minSupplierYears` | on each row |
| `minSupplierRating` | on each row; 4.5 and 5 also use Alibaba's filter |
| `companyCertifications` | Alibaba's filter with the first name, and on each row for any of them (ISO, BSCI, IATF 16949) |
| `excludeSupplierIds` | supplier ids left out, free, never counted against a cap |

#### Product

| Setting | What it does |
|---|---|
| `productCertifications` | Alibaba's filter with the first name, and on each row for any of them (CE, ROHS, FCC, UL) |
| `readyToShip` | Alibaba's Ready to Ship filter, and on each row |
| `samplesAvailable` | Alibaba's samples filter (not checked on the row, which carries no sample flag); ads are left out under it |
| `productTagId` | Alibaba's product tag filter, and on each row |
| `maxLeadTimeDays` | on each row, from the search card's lead time |
| `excludeAds` | on each row: paid placements left out, free |
| `onlyTitleMatches` | on each row: offers whose title holds fewer than half of the keyword's words are left out, free |
| `excludeOfferIds` | offer ids of earlier runs left out, free |

#### Product details and delivery

| Setting | What it does |
|---|---|
| `includeDetails` | reads each delivered offer's product page, one at a time about 6 seconds apart, billed as one Product detail per page read |
| `shipsFromCountries` | on the product page: only offers that list one of these places of dispatch (needs `includeDetails`) |
| `shipToCountry` | reads Alibaba as a buyer in this country (71 countries) through an Apify residential exit there: delivery dates and shipping costs are that country's, prices stay in USD; billed once per run as Delivery country. Each result page is then read through a residential exit, which costs far more than a normal read: keep `maxResultsPerKeyword` at 20 or more per keyword, or the run stops early with a free row that says so |
| `includePersonalData` | with details, adds the supplier's contact person as the product page shows them; off by default |

#### Advanced

`includeRawOffer` (Alibaba's own offer object under `raw`), `extendOutputFunction` (your JavaScript function runs on each row
in a separate sealed process with no access to the run's secrets, files or the network, and its result is stored under `custom`), `maxConcurrency` (1 to 3 result pages in flight, default 2),
`maxRequestRetries` (0 to 5, default 2), `maxRunSeconds`, `debugLog` and `proxyConfiguration` (left out: the run's own
address with one Apify datacenter session behind it; or Apify datacenter from the start, or Apify residential with a
country).

Example: verified manufacturers in China or Vietnam, a largest MOQ of 100, priced at 200 pieces:

```json
{
  "keywords": ["silicone spatula set"],
  "supplierCountries": ["CN", "VN"],
  "verifiedOnly": true,
  "businessTypes": ["manufacturer"],
  "maxMoq": 100,
  "orderQuantity": 200,
  "maxResultsPerKeyword": 50
}
```

### FAQ

#### How does Alibaba pricing work (price ranges and quantity tiers)?

An offer shows a price range and, on 67.9 percent of offers, a quantity ladder of 2 or more tiers whose unit price falls as
the order grows, so the low end of the range is the price at the largest order. Each row carries the ladder in USD (`priceTiers`), the range
(`priceMin`, `priceMax`) and the price at the minimum order (`unitPriceAtMoq`). `priceBasis` says where that price came from:
a ladder, a single price, or a range that depends on the variant (`price_range`, where `unitPriceAtMoqMin` and
`unitPriceAtMoqMax` give the range).

#### Why is the listed price lower than what the supplier quotes?

The low end of an Alibaba price range is the bulk price at the largest order: on 9 product ideas checked by hand, it missed
the price at the minimum order by up to 60 percent. This Actor reports the price at the minimum order (`unitPriceAtMoq`,
equal to the product page's price at MOQ on 76 of 76 laddered or single priced offers checked) and, with `orderQuantity`,
the price at your own quantity.

#### What does MOQ mean on Alibaba, and how do I find low MOQ suppliers?

MOQ is the minimum order quantity a supplier sets for an offer; every row carries it as a number with its unit (`moq`,
`moqUnit`, and Alibaba's text in `moqText`). Set `maxMoq`, for example 10, to keep only offers you can order in that quantity
or less: Alibaba's own filter, checked again on each row.

#### How do I export Alibaba products to CSV or Excel?

Run the Actor with your keywords and open the dataset: the Offers view shows the offer columns (price at MOQ, unit, MOQ,
supplier) and the Price summaries view the summary columns. Every row type is in the dataset, so keep the rows whose `type`
is `offer` (or `keywordSummary`) in your spreadsheet, or ask the API for them. Both download as CSV, Excel or JSON from the
run or through the API.

#### Does Alibaba have a product search API?

This Actor works as one: call `automation_craft/alibaba-scraper` through the Apify API with keywords, links or category ids
and read the rows as JSON (examples below). It needs no Alibaba account or key, and reads Alibaba logged out.

#### Why does this Actor run with limited permissions?

Least privilege: it only reads and writes its own run's storages (the run's dataset and key value store). This Actor opens
no named store, so it cannot read anything else in your account.

### What this Actor does NOT do

- No Alibaba Guaranteed badge or filter: no Guaranteed flag is served on the search data or the product pages this Actor
  reads (0 of 15,185 saved search rows of 4,820 distinct offers, 0 of 139 product pages, and none of the 4,359 rows this Actor
  delivered in its own test runs).
- No standard or worldwide marketplace switch: the worldwide tab parameter changed nothing in the search data this Actor
  reads (3 tests).
- No store review lists and no supplier verification reports: both live on supplier pages under `/company_profile/`, which
  the supplier sites' robots.txt disallows. Rows carry the store rating, review count, service, shipping and product scores
  and review tags, the inspection company (`supplier.inspectedBy`), the company certifications and the profile link.
- No supplier search: this Actor delivers product offers, each with its supplier's facts, not supplier rows found by a
  supplier search.
- No buying requests (RFQ): those live on another Alibaba site, which this Actor does not read.
- No monitor of new or changed offers: each run delivers what it reads. To skip offers you already have, pass their ids in
  `excludeOfferIds` (free).
- No feedback note in the input: Apify gives a developer no access to other users' runs or inputs, so a note there cannot
  reach us. Please use the Issues tab.
- The summary statistics are over the offers this run delivered for a search, not over the whole of Alibaba's market for the
  keyword.
- Prices stay in USD, as Alibaba serves them: no conversion. A row Alibaba serves in another currency carries no USD figures
  (`currency` empty), never a converted one.
- Alibaba's order of page 1 changes between calls (5 calls in 77 seconds gave 5 orders), so two runs of one keyword deliver
  overlapping but not equal offers. `totalReported` on the coverage row is Alibaba's own count and moves between calls too.
- No more than 20 pages (960 offers) per search: pages 21 to 24 bring few or no new offers, and page 21 can re-serve pages 1
  to 20 in one oversized answer.
- No solving of Alibaba's slider verification page. When Alibaba shows it, that door closes for the rest of the run, and the
  searches or products it leaves unread get free rows (one move to a fresh address is made only when the page comes within a
  door's first 3 calls).
- No checking of the category or the samples filter on the row: Alibaba alone applies them.
- No use of your own proxy links.
- Personal data is off by default: the supplier's contact person (name, gender, job title, photo) is empty unless you turn
  `includePersonalData` on. You are responsible for a lawful use of personal data, GDPR included.

### API

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~alibaba-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["yoga mat"], "maxResultsPerKeyword": 20}'
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('automation_craft/alibaba-scraper').call({ keywords: ['yoga mat'], maxResultsPerKeyword: 20 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const offers = items.filter((r) => r.type === 'offer');
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("automation_craft/alibaba-scraper").call(run_input={"keywords": ["yoga mat"], "maxResultsPerKeyword": 20})
items = client.dataset(run["defaultDatasetId"]).list_items().items
summary = [r for r in items if r["type"] == "keywordSummary"]
```

### Changelog

- 0.1 (2026-11): first release. Offers by keyword, search link, category or product link with the USD price per unit at the
  minimum order, the quantity price ladder, MOQ and unit, supplier facts and the ad flag; a price summary row per search; the
  Product detail add-on. The full list is on the Changelog tab.

### More data tools by Automation Craft

- [IndiaMART Scraper: B2B Products, Prices, Suppliers](https://apify.com/automation_craft/indiamart-scraper)
- [AliExpress Search Scraper - Products and Prices](https://apify.com/automation_craft/aliexpress-search-scraper)
- [Amazon Product Scraper - Search, Best Sellers](https://apify.com/automation_craft/amazon-data-scraper)
- [Amazon Sponsored Products Scraper - Ads by Keyword](https://apify.com/automation_craft/amazon-sponsored-products-scraper)
- [Walmart Scraper: Products, Prices, Sellers](https://apify.com/automation_craft/walmart-scraper)
- [Etsy Scraper: Listings, Prices, Ads, Reviews](https://apify.com/automation_craft/etsy-scraper)

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/alibaba-scraper/changelog.md

# Actor input Schema

## `keywords` (type: `array`):

Product words as you would type them on Alibaba.com, one search each (for example yoga mat, steam cleaner handheld). Duplicates are read once. An Alibaba search or product link pasted here is read as a link. A search whose first page holds no offer whose title carries the words delivers nothing and is not charged.

## `searchUrls` (type: `array`):

Links copied from alibaba.com: trade/search?SearchText=..., search/page?SearchText=..., catalog/<name>\_cid<id>, or a showroom page products/<words>.html (read as a search of its words). Their words, category, page and filters (price, MOQ, verified, verified pro, supplier country, ready to ship, certifications, store rating, samples, sales order) are applied; a setting you give below replaces the link's own. A link with a parameter this Actor does not read is refused with a free row naming it.

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

Alibaba product pages (alibaba.com/product-detail/...\_<id>.html) or bare product ids. Each delivered product row is billed as one Product detail; a product Alibaba does not show to the run's address is a free row.

## `categoryIds` (type: `array`):

Alibaba category ids (the digits after \_cid in a catalog link, or categoryId in a search link). With keywords, each keyword is searched inside each category; given alone, each category is browsed without words.

## `maxResultsPerKeyword` (type: `integer`):

Most offers delivered per search (a keyword, link or category, per supplier country). 1 to 960: Alibaba serves 20 pages of 48 offers to one search.

## `maxPagesPerKeyword` (type: `integer`):

Most result pages of 48 offers read per search, 1 to 20. Left out: up to 20 in Alibaba's own orders, 1 with a price or response rate order (which sorts the offers read).

## `summaryOffers` (type: `integer`):

How many of each search's first offers priced per item (in Alibaba's order, inside your price range) the summary row's first offers figure counts: 5 to 50. Left out: 10. The summary headline uses this figure when fewer than 5 offers have every keyword word in their title.

## `startPage` (type: `integer`):

The result page each search starts at (1 to 20). Left out: page 1, or a search link's own page.

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

Most offer and product rows the whole run delivers and bills, a hard ceiling on its cost (1 to 100,000).

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

best_match (Alibaba's order) or sales (Alibaba's best sellers of the last 180 days); price_low, price_high and response_rate sort the offers this run read (Alibaba serves no such order), and each row says so. Left out: best match, or a search link's own order.

## `minPrice` (type: `number`):

Alibaba's own price filter, in USD per unit. Each row then says outOfRange: true when its price at the minimum order lies outside your range; the summary leaves those rows out of its figures.

## `maxPrice` (type: `number`):

Alibaba's own price filter, in USD per unit (see the lowest price).

## `minMoq` (type: `integer`):

Only offers whose minimum order quantity is at least this (checked on each row).

## `maxMoq` (type: `integer`):

Only offers you can order in this quantity or less, for example 10 for small test orders (Alibaba's own filter, checked on each row).

## `orderQuantity` (type: `integer`):

Adds unitPriceAtQuantity to every row: the price per unit at this quantity, read from the offer's ladder (empty below the offer's minimum order).

## `supplierCountries` (type: `array`):

Two letter codes or English names (CN, IN, VN, TR, US). Each search is read once per country with Alibaba's own country filter.

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

Suppliers checked by a third party inspection company (Alibaba's Verified badge).

## `verifiedProOnly` (type: `boolean`):

Alibaba's Verified Pro suppliers.

## `tradeAssuranceOnly` (type: `boolean`):

Suppliers that take Trade Assurance orders (checked on each row; almost every supplier does).

## `businessTypes` (type: `array`):

Only suppliers of these business types: manufacturer, trading_company, distributor, buying_office, other. With Verified suppliers only, manufacturer gives verified manufacturers.

## `minSupplierYears` (type: `integer`):

Only suppliers with at least this many years on Alibaba.com (checked on each row).

## `minSupplierRating` (type: `number`):

Only suppliers with at least this store rating out of 5 (4.5 and 5 use Alibaba's own filter; every value is checked on each row).

## `companyCertifications` (type: `array`):

Only suppliers holding one of these management certifications, for example ISO, BSCI, IATF 16949 (Alibaba's own filter with the first, every row checked for any of them).

## `excludeSupplierIds` (type: `array`):

Supplier ids (supplier.id of earlier rows) whose offers are left out, free; they never count against a cap. Up to 100,000.

## `productCertifications` (type: `array`):

Only offers that show one of these product certifications, for example CE, ROHS, FCC, UL (Alibaba's own filter with the first, every row checked for any of them).

## `readyToShip` (type: `boolean`):

Alibaba's Ready to Ship offers.

## `samplesAvailable` (type: `boolean`):

Alibaba's filter for offers you can order a sample of. Ads are left out under it (an ad slot need not follow the filter); with product details on, each row shows the sample price.

## `productTagId` (type: `string`):

An Alibaba internal product tag id (7 to 16 digits) sent as Alibaba's product tag filter; rows that do not carry the tag are left out, free.

## `maxLeadTimeDays` (type: `integer`):

Only offers whose lead time on the search card is at most this many days.

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

Leave out offers placed by paid ads (isAd); they are free. Off: ads are delivered with isAd true.

## `onlyTitleMatches` (type: `boolean`):

Leave out, free, offers whose title holds fewer than half of the keyword's words (Alibaba also returns related products). Off: every row says titleMatchesKeyword.

## `excludeOfferIds` (type: `array`):

Offer ids (offerId of earlier rows) left out, free. Up to 100,000.

## `includeDetails` (type: `boolean`):

Also read each delivered offer's product page: attributes, variants and their prices, customisation, sample price, lead times, packaging, places of dispatch, certifications with validity and the supplier's page facts. Billed as one Product detail per row whose page was read. Pages are read one at a time, about 6 seconds apart.

## `shipsFromCountries` (type: `array`):

Only offers whose product page lists one of these places of dispatch (local stock), as two letter codes. Needs Product details.

## `shipToCountry` (type: `string`):

Read Alibaba as a buyer in this country (two letter code, for example DE, GB, AU) through an Apify residential exit there: delivery dates and shipping costs are that country's. Prices stay in USD. Billed once per run as Delivery country. Residential reads cost more: keep maxResultsPerKeyword at 20 or more, or the run stops early with a free row that says so. Left out: as a buyer in the United States.

## `includePersonalData` (type: `boolean`):

With Product details, adds the supplier's contact person as the product page shows them (name, first and last name, gender, job title, photo). Off: those fields are empty. You are responsible for a lawful use of personal data, GDPR included.

## `includeRawOffer` (type: `boolean`):

Adds raw: the source's own offer object of each search row, as served (ad creative payloads left out).

## `extendOutputFunction` (type: `string`):

A JavaScript function that gets each row and returns an object stored under custom on that row, for example (row) => ({ perDozen: row.unitPriceAtMoq \* 12 }). It runs in a separate sealed process with no access to the run's secrets, files or the network, one second at most per row.

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

Result pages of one search requested at once (1 to 3). Product pages are always read one at a time.

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

Times a failed request is asked again (0 to 5).

## `maxRunSeconds` (type: `integer`):

The run stops reading after this many seconds and writes its rows, summaries and status (30 to 86,400).

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

Write detailed log lines.

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

Left out: the run reads from its own address with one Apify datacenter session behind it. Or Apify datacenter from the start (apifyProxyGroups BUYPROXIES94952), or Apify residential with a country (the same as Delivery country). Own proxy links are not used.

## Actor input object example

```json
{
  "keywords": [
    "yoga mat"
  ],
  "maxResultsPerKeyword": 20,
  "maxItems": 1000,
  "includeDetails": false,
  "includePersonalData": false,
  "includeRawOffer": false,
  "maxConcurrency": 2,
  "maxRequestRetries": 2,
  "debugLog": false
}
```

# Actor output Schema

## `items` (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 = {
    "keywords": [
        "yoga mat"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/alibaba-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 = { "keywords": ["yoga mat"] }

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/alibaba-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 '{
  "keywords": [
    "yoga mat"
  ]
}' |
apify call automation_craft/alibaba-scraper --silent --output-dataset

```

## MCP server setup

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