# AliExpress Scraper Pro — Product Details & Price Monitoring (`datarock/aliexpress-search-pro`) Actor

AliExpress search + product pages: variants/SKU, shipping, delivery, seller, specs. All result pages, dedupe and price/orders monitoring. JSON/CSV.

- **URL**: https://apify.com/datarock/aliexpress-search-pro.md
- **Developed by:** [Data Rock](https://apify.com/datarock) (community)
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 product from searches

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/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

## AliExpress Product Scraper Pro — Prices, Variants & Shipping

AliExpress search plus product pages: variants and SKU stock, shipping and delivery, store and seller data, specs and all images. Mix keywords, product URLs and IDs in one list, and monitor price and orders changes on a schedule.

> Pricing: pay per event, see the Pricing tab. Events: `search` (a product row from keyword search) and `details` (a product row whose product page was extracted).
>
> Not affiliated with AliExpress or Alibaba. Not endorsed by or sponsored by AliExpress or Alibaba Group. "AliExpress" is a trademark of its owner.

### What you get

- **Keywords, product URLs or product IDs** mixed in `keywords` (auto-detected). No keyword limit.
- **Product pages** (`includeDetails`, on by default): `variants` (`skuId`, `attributes`, `price`, `originalPrice`, `stock`, `available`), `variantCount`, `totalStock`, `shippingOptions`, `shippingFrom`, `shippingFee`, `freeShipping`, `deliveryDaysMin`/`deliveryDaysMax`, `deliveryEstimate`, `storeName`, `storeId`, `storeUrl`, `sellerId`, `storeRating`, `storePositiveRate`, `storeFeedbackCount`, `storeCountry`, `topRatedSeller`, `storeOpenedAt`, `specs`, `images`, `ratingDetail`, `reviewCount`, `descriptionUrl`, `categoryId`, `categoryPath`, `globalProductId`.
- **Result pages per keyword:** `maxPagesPerKeyword`, 1 by default (up to 200), 60 products per page. Search pages need no browser.
- **Blocked product pages are retried.** If a product page still fails, the product keeps its search data and gets `status: "partial"` and a `detailStatus` (`blocked`, `failed` or `skipped`). If the run stops early, products not yet opened come out with `detailStatus: "skipped"` instead of being dropped.
- **`includeDetails` off = search data only.** No product page is opened. Product URL/ID inputs then return a bare row (ID and link only).
- **Keyword problems** (`no_results`, `blocked`, `error`, `skipped`) are listed in the `RUN_REPORT` record (`keywordStatus`), not in the dataset. The dataset holds products only. When AliExpress finds nothing that matches a query and shows recommendations instead, the keyword returns 0 products and `no_results`.
- **Dedupe** across keywords (`matchedKeywords`).
- **Monitoring:** `onlyNewOrChanged` returns only new products or those whose `salePrice`, `originalPrice` or `soldCount` changed, with `changeType` (`new` or `changed`), `changedFields`, `previousPrice`, `previousOriginalPrice`, `previousSoldCount`, `previousSeenAt`. State is kept in the named key-value store `aliexpress-pro-state` under `stateKey`. Products found by keyword search that did not change are not opened. Product URLs and IDs are opened first and compared afterwards; unchanged ones are dropped.
- **Caps:** `maxItems`, `maxItemsPerKeyword`, `maxPagesPerKeyword`, `keywordTimeoutSecs` (search paging per keyword, default 300 s), `maxRunSeconds` (default 240 s; the run also stops ~45 s before the platform run timeout, default 600 s, so data and RUN_REPORT are always saved) and `maxCostUsd` (in-run cost estimate). When a cap is reached the run stops cleanly; unfinished products get `status: "partial"` and `detailStatus: "skipped"`.
- **Flat or nested output** (`outputFormat`) for spreadsheets or JSON.

### Pricing

Pay per event. The current event prices are shown on the Pricing tab in Apify Console.

- `search` event: product search results. See the Pricing tab.
- `details` event: product page details. See the Pricing tab.
- Some product pages may not load during a run. Those rows still return search fields, marked with `status: "partial"` and a `detailStatus` of `blocked`, `failed` or `skipped` (run limit reached).
- A tiny Apify start event applies to each run.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `keywords` | array of strings | prefill `["wireless earbuds"]` (required) | Search phrases, AliExpress product URLs or product IDs, mixed in one list. |
| `sortBy` | string | `default` | `default`, `orders`, `priceAsc`, `priceDesc`. |
| `shipTo` | string | `US` | ISO-2 country code. Affects prices, shipping and availability. |
| `currency` | string | `USD` | ISO-4217 code. |
| `language` | string | `en` | Language code (en, es, fr, de, pt, it, ru...). |
| `maxItemsPerKeyword` | integer | `20` | Max products per keyword (0 = until the end of results or `maxPagesPerKeyword`). |
| `maxPagesPerKeyword` | integer | `1` | Max result pages per keyword (1–200). |
| `maxItems` | integer | `0` | Max products per run (0 = no limit). |
| `includeDetails` | boolean | `true` | Open product pages for full details. Off = search data only (faster); no product page is opened. |
| `detailsConcurrency` | integer | `5` | Parallel product pages (1–20). |
| `dedupe` | boolean | `true` | One row per product across keywords. |
| `onlyNewOrChanged` | boolean | `false` | Monitoring mode. |
| `stateKey` | string | derived | Name of the monitoring memory, to share or separate it between schedules. Default is derived from keywords, ship-to, currency, language and sort. |
| `keywordTimeoutSecs` | integer | `300` | Time limit for search paging per keyword (10–86400 s). |
| `maxRunSeconds` | integer | `240` | Max run time (30–86400 s). |
| `maxCostUsd` | number | `0` (off) | Stops the run cleanly when the in-run cost estimate reaches this amount in USD. It is an estimate, not an invoice. Separate from Apify's "max total charge" run option. |
| `outputFormat` | string | `nested` | `nested` or `flat`. |
| `proxyConfiguration` | object | Preset in the input | Connection settings. The country follows `shipTo` unless you set one. |
| `saveRawSample` | boolean | `false` | Debug: saves the first raw product-page response to the key-value store as `DETAIL_SAMPLE`. |

### Output fields

Dataset rows have `dataType` = `aliexpressProduct`.

- **Search fields:** `status` (`ok` or `partial`), `keyword`, `page`, `rank`, `id`, `skuId`, `title`, `url`, `image`, `salePrice`, `priceSource`, `originalPrice`, `discountPercent`, `currency`, `rating`, `soldText`, `soldCount`, `isAd`, `shipTo`, `scrapedAt`, `errorMessage`.
- **`priceSource`:** where `salePrice` came from. `salePrice` = the price shown on the search card. `utLogFallback` = a fallback used when the card shows no price block; it is often a new-buyer promo (welcome deal) price and may differ from the regular price. `variantMin` = the lowest variant price from the product page (rows from product URLs or IDs). `null` = no price found.
- **Run fields:** `matchedKeywords`, `fromProductInput` (true for rows that came from a product URL or ID), `detailStatus` (`ok`, `blocked`, `failed`, `skipped`).
- **Product-page fields:** `detailTitle`, `images`, `variants`, `variantCount`, `totalStock`, `shippingOptions`, `shippingFrom`, `shippingFee`, `freeShipping`, `deliveryDaysMin`, `deliveryDaysMax`, `deliveryEstimate`, `storeName`, `storeId`, `storeUrl`, `sellerId`, `storeRating`, `storePositiveRate`, `storeFeedbackScore`, `storeFeedbackCount`, `storeCountry`, `topRatedSeller`, `storeOpenedAt`, `specs`, `ratingDetail`, `reviewCount`, `descriptionUrl`, `categoryId`, `categoryPath`, `globalProductId`.
- **Monitoring fields:** `changeType`, `changedFields`, `previousPrice`, `previousOriginalPrice`, `previousSoldCount`, `previousSeenAt`.

Fields AliExpress does not show are `null`. With `outputFormat: "flat"`, `images`, `specs`, `shippingOptions`, `matchedKeywords` and `changedFields` become `|`-joined text and `variants` becomes JSON text.

### Recipes

- **Price & orders tracker:** schedule with `onlyNewOrChanged: true` and a `stateKey`; send changes to Google Sheets or Slack via the Apify app in n8n/Make.
- **Dropshipping research:** keyword → `sortBy: orders` → details for top products.
- Works from the Apify API, client libraries and the Apify MCP server.

### FAQ

**How is it different from the free version?** Pro adds product pages, URL/ID input, no keyword limit, no product cap, more result pages, dedupe and monitoring.
**How much does it cost?** Pay per event; see the Pricing tab. Events: `search` (a product row from keyword search) and `details` (a product row whose product page was extracted).
**Can I cap my spend?** Yes: `maxItems`, `maxCostUsd`, and Apify's own max total charge. When the max total charge is reached the run stops cleanly and no further rows are added.
**Can I set ship-to country and currency?** Yes, `shipTo` and `currency`.
**Review texts?** Not included; `reviewCount` and `ratingDetail` are.
**Login?** No. Only public pages; no account used.
**Personal data?** Product and store data only; buyer data is not collected.

# Actor input Schema

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

Search phrases, AliExpress product URLs (…/item/1005….html) or product IDs, mixed in one list (auto-detected). No limit.

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

Order of search results.

## `shipTo` (type: `string`):

ISO-2 code (US, GB, DE, FR, BR...). Affects prices, shipping and availability. The connection country follows it unless you set one.

## `currency` (type: `string`):

ISO-4217 code (USD, EUR, GBP...).

## `language` (type: `string`):

en, es, fr, de, pt, it, ru... (titles are returned in this language when AliExpress has a translation).

## `maxItemsPerKeyword` (type: `integer`):

0 = page through to the end of the results (or Max pages per keyword).

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

60 products per page (about 48 new after duplicates). Default 10 pages; allowed 1-200, tested up to 10 pages.

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

Max products for the whole run (0 = no limit).

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

Adds variants/SKUs (price, stock), shipping options, ship-from and delivery estimate, store name/ID/URL/rating, specs, all images, review count. Off = search data only (faster); no product page is opened.

## `detailsConcurrency` (type: `integer`):

Higher = faster.

## `dedupe` (type: `boolean`):

One row per product; 'matchedKeywords' lists all keywords that returned it.

## `onlyNewOrChanged` (type: `boolean`):

For schedules: return only products that are new or whose price, original price or sold count changed, with previous values and 'changedFields'. Unchanged products are not re-opened. State kept in your named key-value store 'aliexpress-pro-state'.

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

Custom name for the monitoring memory, to share or separate it between schedules. Default: derived from keywords, ship-to, currency, language and sort.

## `keywordTimeoutSecs` (type: `integer`):

Search paging for a keyword stops at this limit and keeps the products found so far.

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

The run stops cleanly and saves results when this time is reached; unfinished products get status 'partial'. The run also stops early enough (about 45 s before) to save data and RUN_REPORT before the platform run timeout.

## `maxCostUsd` (type: `number`):

Stops the run cleanly when the in-run cost estimate reaches this amount in USD. It is an estimate, not an invoice; unfinished products get status 'partial'. Separate from Apify's own 'max total charge' run option. 0 = no limit.

## `outputFormat` (type: `string`):

'flat' turns variants, specs, images and shipping options into text columns.

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

Connection settings. The country follows the ship-to country unless you set one.

## `saveRawSample` (type: `boolean`):

Saves the first raw product-page response to the key-value store as DETAIL_SAMPLE.

## Actor input object example

```json
{
  "keywords": [
    "wireless earbuds"
  ],
  "sortBy": "default",
  "shipTo": "US",
  "currency": "USD",
  "language": "en",
  "maxItemsPerKeyword": 20,
  "maxPagesPerKeyword": 1,
  "maxItems": 0,
  "includeDetails": true,
  "detailsConcurrency": 5,
  "dedupe": true,
  "onlyNewOrChanged": false,
  "keywordTimeoutSecs": 300,
  "maxRunSeconds": 240,
  "maxCostUsd": 0,
  "outputFormat": "nested",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "saveRawSample": false
}
```

# Actor output Schema

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

All products (one row per product), as JSON/CSV/Excel. Keyword-level problems are in the RUN_REPORT record, not here.

## `consoleRun` (type: `string`):

No description

## `runReport` (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": [
        "wireless earbuds"
    ],
    "maxItemsPerKeyword": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("datarock/aliexpress-search-pro").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": ["wireless earbuds"],
    "maxItemsPerKeyword": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("datarock/aliexpress-search-pro").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": [
    "wireless earbuds"
  ],
  "maxItemsPerKeyword": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call datarock/aliexpress-search-pro --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datarock/aliexpress-search-pro"
        }
    }
}
```

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/EAIJWYloKOMr5rv1g/builds/qegYe9rM47OoBgtLc/openapi.json
