# Alibaba Supplier Catalogue (`apt_marble/alibaba-supplier-products-scraper`) Actor

Export any Alibaba supplier's whole catalogue as one clean table: every product with its published price band, minimum order and unit, catalogue group, certificates and today's discount. Every row carries the supplier id, so it joins straight to your supplier list.

- **URL**: https://apify.com/apt\_marble/alibaba-supplier-products-scraper.md
- **Developed by:** [Hamza](https://apify.com/apt_marble) (community)
- **Categories:** E-commerce
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.20 / 1,000 product exporteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Alibaba Supplier Catalogue

Paste a supplier's Alibaba storefront address and get their entire published
product catalogue as one clean table — every product, its published price band,
the minimum order and the unit it is counted in, the supplier's own catalogue
groups, certificates, pictures and video flag, and today's discounted price
where the supplier is running one. Every row carries the owning supplier's id,
so a catalogue export drops straight next to a supplier list and joins on one
column. No account and no login are needed.

### What you can do with it

- **Price a supplier properly before you contact them.** See their whole range
  at once — the cheapest line, the dearest, where the minimum order jumps — and
  decide whether they are worth an enquiry at all.
- **Compare two suppliers line by line.** Export both catalogues, match on the
  product group, and see who is cheaper on the exact item you want rather than
  on the one they chose to put on their homepage.
- **Spot today's discounts.** Products where the supplier is currently selling
  below their standing asking price come back with both figures and a flag, so
  a real promotion is obvious and a fake one is not.
- **Search inside one supplier.** Give a term and get only their matching
  products, using the supplier's own in-store search rather than a filter
  applied afterwards.
- **Track a competitor's range over time.** Schedule the same storefronts
  weekly and watch products, price bands and minimum orders move.
- **Build a sourcing sheet.** Every field is a plain column — export to Excel,
  Google Sheets, CSV or JSON in one click.

### What you get

One row per product. Abridged real example:

```json
{
  "supplierId": "273706047",
  "supplierName": "Shandong Jianha Baofa Heavy Industry Machinery Co., Ltd.",
  "supplierSubdomain": "jianha",
  "supplierUrl": "https://jianha.en.alibaba.com/",
  "supplierLocation": "Shandong, China",
  "supplierCountryCode": "CN",
  "verifiedSupplier": true,
  "searchText": null,
  "catalogPage": 1,
  "positionOnPage": 1,
  "catalogPosition": 1,
  "productId": "1601622767452",
  "title": "Y32-315 Hydraulic Crimping Tool Special for Aluminum Alloy Wire Nose",
  "url": "https://www.alibaba.com/product-detail/Y32-315-Hydraulic-Crimping-Tool-Special_1601622767452…",
  "productGroupId": "917957129",
  "productGroupName": "Four Column Press Machine",
  "productGroupPath": ["Four Column Press Machine"],
  "imageUrl": "…/Hc4dd291dd19c45a983983a2b809d61c8q.jpg_350x350.jpg",
  "imageCount": 6,
  "hasVideo": true,
  "currency": "USD",
  "priceMin": 18000,
  "priceMax": 20000,
  "priceText": "$18,000-20,000 / piece",
  "priceIsRange": true,
  "quoteOnRequest": false,
  "priceUnit": "piece",
  "minOrderQuantity": 1,
  "minOrderUnit": "piece",
  "minOrderText": "1 piece",
  "listPrice": 18000,
  "discountedPrice": null,
  "onPromotion": false,
  "readyToShip": false,
  "certificates": ["CE"],
  "orderCount": null,
  "soldLast180Days": null,
  "scrapedAt": "2026-08-09T20:06:00.185Z"
}
```

### Input reference

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `supplierUrls` | list of text | `["https://jianha.en.alibaba.com/"]` | The storefront address of each supplier whose catalogue you want. The short name on its own works too. Up to 10 per run. |
| `searchText` | text | — | Return only the supplier's products matching this term, using their own in-store search. Leave empty for the whole catalogue. |
| `maxProductsPerSupplier` | number | `96` | How many products to collect from each supplier (maximum 6,400). |
| `country` | select | United States | Which country's version of the site to read. |
| `onlyPricedProducts` | true/false | `false` | Drop products where the supplier publishes no price. Off by default, so those come back marked instead. |
| `onlyReadyToShip` | true/false | `false` | Keep only stock held for immediate dispatch. Many suppliers publish none. |
| `includeLivePrices` | true/false | `true` | Attach the price the supplier is charging today alongside their standing asking price. |
| `maxCatalogPagesPerRun` | number | `24` | Total catalogue pages the whole run may collect, sixteen products to a page (maximum 40). |
| `delayBetweenPagesSeconds` | number | `3` | How long to wait between catalogue pages (2–15). |
| `parallelSuppliers` | number | `2` | How many storefronts to work through at the same time (1–2). |

### Output fields

| Field | Type | Description |
| --- | --- | --- |
| `supplierId` | text | The supplier's identifier on the site — the column to join a catalogue export to a supplier list on. |
| `supplierName` | text | The supplier's registered trading name, when the storefront shows it. A storefront filtered to one search term does not always display it, so this can be empty where `supplierId` is not. |
| `supplierSubdomain`, `supplierUrl` | text | The storefront this product came from. |
| `supplierLocation`, `supplierCountryCode` | text | Where the supplier is based. |
| `verifiedSupplier` | true/false | Whether the storefront states it has passed the site's supplier inspection. Empty when the storefront did not say. |
| `searchText` | text | The in-store search this product came from, empty for a full catalogue export. |
| `catalogPage`, `positionOnPage`, `catalogPosition` | number | Where the product sat in the supplier's own ordering. |
| `productId` | text | The product's identifier on the site. |
| `title` | text | Product title as the supplier wrote it. |
| `url` | text | Direct link to the product. |
| `productGroupId`, `productGroupName`, `productGroupPath` | text / list | The supplier's own catalogue shelf for this product, including the full path when it is nested. |
| `imageUrl`, `images`, `imageCount` | text / list / number | Preview picture and every full-size picture on the listing. |
| `hasVideo`, `videoId` | true/false / text | Whether the listing includes a product video. |
| `currency` | text | The currency this row is quoted in, taken from the row itself. Supplier catalogues quote US dollars. A figure whose currency cannot be established is left out of the row rather than written into a column labelled with a different one. |
| `priceMin`, `priceMax` | number | The supplier's published asking-price band for one unit. |
| `priceText` | text | The same band exactly as the supplier prints it, including the unit. |
| `priceIsRange` | true/false | Whether the supplier published a band rather than one figure. |
| `quoteOnRequest` | true/false | True when the supplier publishes no price at all and wants an enquiry instead. |
| `priceUnit` | text | The unit the price is quoted per — piece, set, unit, and so on. |
| `minOrderQuantity`, `minOrderUnit`, `minOrderText` | number / text | Smallest order the supplier accepts, split out and as printed. |
| `listPrice` | number | The standing asking price checked at collection time. |
| `discountedPrice` | number | What the supplier is charging today, when that is lower. Empty when there is no discount. |
| `onPromotion` | true/false | Whether a discount was in force at collection time. Empty when today's price was not checked, or could not be established — never `false` on the strength of no information. |
| `freightEstimate` | number | The supplier's own shipping estimate, in the same currency, when they publish one. |
| `readyToShip` | true/false | Whether the supplier holds this in stock for immediate dispatch. |
| `certificates`, `certificateLogos` | list | Product certificates the supplier displays, with their badge pictures. |
| `attributes` | list | Extra supplier-typed labels, where a supplier publishes any. |
| `orderCount`, `soldLast180Days`, `viewsLastMonth`, `productReviewScore` | number | Demand figures. Supplier catalogues almost never publish these, so they are normally empty — see the limits below. |
| `scrapedAt` | text | When the row was collected. |

### Pricing

Pay per result. You are charged for each product added to your results and for
nothing else — a storefront that turns out to be empty, or one that could not
be opened, costs nothing.

| What is charged | Price |
| --- | --- |
| Product exported | $0.0012 each — $1.20 per 1,000 products |

A worked example: one supplier's first 96 products costs $0.12. A complete
export of a large supplier's 851-product catalogue costs $1.02 in total, spread
over the two or three runs such a catalogue takes. Ten suppliers at 200 products
each costs $2.40.

### Limits & what this actor cannot do

- **Catalogues are collected in measured helpings.** Each run collects up to
  the catalogue page allowance you set, sixteen products to a page. A very
  large supplier can use the whole allowance on their own; when that happens
  the run stops cleanly, tells you exactly how many products it collected out
  of how many the supplier publishes, and leaves the rest for the next run.
  Collecting a big catalogue across two or three scheduled runs is normal and
  is more reliable than trying to take it in one.
- **The source can decline further reading.** If it does, the run stops rather
  than pressing on, reports that it stopped, and the remaining suppliers are
  reported as not reached rather than as empty. Trying again about half an hour
  later normally works.
- **Searching inside a catalogue goes as far as the storefront offers it.**
  When a supplier's storefront stops offering further results for your term,
  the run stops there and says so, rather than quietly widening the search back
  out to their whole catalogue.
- **Prices are the supplier's published asking price.** The price actually
  agreed in a negotiated order is not published anywhere and is not returned.
- **Some suppliers publish no price and invite an enquiry instead.** Those
  products come back flagged, never as a zero price.
- **The full quantity-break table is not part of a storefront catalogue.** A
  supplier's catalogue publishes the asking-price band and the minimum order;
  the deeper "buy 500 and pay this, buy 5,000 and pay that" table lives on the
  individual product page and is not collected here.
- **Sales, order and view counters are almost never filled in.** Suppliers
  overwhelmingly leave them blank on their catalogue, so these fields come back
  empty rather than as a zero — an empty field means "the supplier did not
  publish it", never "this has never sold".
- **A supplier number on its own cannot be opened.** The site publishes no way
  to reach a storefront from a number, so the actor asks for the storefront
  address and refuses a bare number instead of quietly returning nothing.
- **Contact details a supplier chooses not to publish are not returned**, and
  neither is their company profile page — this actor covers what they sell.
- **Prices, stock and catalogues are a snapshot** at the moment of collection
  and keep changing afterwards.
- **Speed depends on the size of the job and on the source site's own response
  times.** No fixed throughput is promised, and the actor deliberately reads
  storefronts gently.
- **The source site's terms govern automated access.** You are responsible for
  using the data lawfully and in line with those terms, and for handling any
  personal data in line with applicable privacy law.

### FAQ

**Do I need an account on the source site?**
No. Nothing is signed into and no account is involved.

**Does it need my login or password?**
No. It never asks for one and cannot use one.

**Can I schedule it?**
Yes. Schedule it on Apify like any other actor. For a large catalogue, several
smaller scheduled runs work better than one very long one.

**Is the data complete?**
It is everything the supplier publishes on their own storefront catalogue, up
to the limits you set for the run. The summary tells you how many products were
collected against how many the supplier publishes, so you always know whether
you have the whole catalogue or part of it.

**Why is `discountedPrice` empty on most rows?**
Because most products are not discounted. When a supplier is running a
promotion, that row comes back with both the standing price and today's price
and a flag saying so.

**Can I get the price at 500 units, or at 5,000?**
Not from a storefront catalogue. What a catalogue publishes is the asking-price
band and the minimum order, and that is what you get here — accurately, rather
than a guessed ladder.

**What happens to a supplier whose storefront does not exist?**
It is reported as not published, separately from suppliers that failed to open
and separately from suppliers with an empty catalogue. Three different facts,
three different counts.

# Actor input Schema

## `supplierUrls` (type: `array`):

The storefront address of each supplier whose catalogue you want, for example https://jianha.en.alibaba.com/. The short name on its own works too. Up to 10 suppliers per run.

## `searchText` (type: `string`):

Optional. Return only the supplier's products matching this term, using the supplier's own in-store search. Leave empty for the whole catalogue.

## `maxProductsPerSupplier` (type: `integer`):

How many products to collect from each supplier. Large catalogues are collected in order, newest first, and the run tells you exactly where it stopped.

## `country` (type: `string`):

Which country's version of the site to read. Supplier catalogues publish their asking prices in US dollars for every country, so this changes the storefront you see rather than the currency.

## `onlyPricedProducts` (type: `boolean`):

Drop products where the supplier publishes no price and invites an enquiry instead. Off by default, so those products are returned and marked as quote-on-request.

## `onlyReadyToShip` (type: `boolean`):

Keep only the products the supplier holds in stock for immediate dispatch. Many suppliers publish none at all.

## `includeLivePrices` (type: `boolean`):

Attach the price the supplier is charging today, so you can see an active discount against the standing asking price. On by default.

## `maxCatalogPagesPerRun` (type: `integer`):

The total number of catalogue pages this run may collect across all suppliers. Sixteen products fit on a page. Keeping this modest is what makes repeated runs reliable; the run stops cleanly when it is spent and reports what it did not collect.

## `delayBetweenPagesSeconds` (type: `integer`):

How long to wait between catalogue pages. Two seconds is the minimum and is usually enough; raise it if you are collecting several large suppliers.

## `parallelSuppliers` (type: `integer`):

How many supplier storefronts to work through at the same time.

## Actor input object example

```json
{
  "supplierUrls": [
    "https://jianha.en.alibaba.com/"
  ],
  "searchText": "press",
  "maxProductsPerSupplier": 100,
  "country": "US",
  "onlyPricedProducts": false,
  "onlyReadyToShip": false,
  "includeLivePrices": true,
  "maxCatalogPagesPerRun": 24,
  "delayBetweenPagesSeconds": 3,
  "parallelSuppliers": 2
}
```

# Actor output Schema

## `products` (type: `string`):

Every product collected from the supplier catalogues in this run, with its price band, minimum order and owning supplier.

## `runSummary` (type: `string`):

Counts per supplier, including any storefront that could not be read, was not published, or was not reached.

# 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 = {
    "supplierUrls": [
        "https://jianha.en.alibaba.com/"
    ],
    "maxProductsPerSupplier": 100,
    "country": "US",
    "maxCatalogPagesPerRun": 24,
    "delayBetweenPagesSeconds": 3,
    "parallelSuppliers": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("apt_marble/alibaba-supplier-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 = {
    "supplierUrls": ["https://jianha.en.alibaba.com/"],
    "maxProductsPerSupplier": 100,
    "country": "US",
    "maxCatalogPagesPerRun": 24,
    "delayBetweenPagesSeconds": 3,
    "parallelSuppliers": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("apt_marble/alibaba-supplier-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 '{
  "supplierUrls": [
    "https://jianha.en.alibaba.com/"
  ],
  "maxProductsPerSupplier": 100,
  "country": "US",
  "maxCatalogPagesPerRun": 24,
  "delayBetweenPagesSeconds": 3,
  "parallelSuppliers": 2
}' |
apify call apt_marble/alibaba-supplier-products-scraper --silent --output-dataset

```

## MCP server setup

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