# AliExpress Products Scraper & Price Tracker (`myth84/aliexpress-search-scraper`) Actor

AliExpress products scraper and price tracker: scrape AliExpress search results for any keywords — price, discount, rating, units sold, ship-from country, free shipping, delivery estimate and image, for your country and currency. Price-drop monitoring. One flat row per product, no personal data.

- **URL**: https://apify.com/myth84/aliexpress-search-scraper.md
- **Developed by:** [Flatrow Data Studio](https://apify.com/myth84) (community)
- **Categories:** E-commerce, Automation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.19 / 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

### AliExpress Products Scraper & Price Tracker – prices and sales, no personal data

AliExpress products scraper and AliExpress price tracker: get product prices, discounts, ratings, units sold and shipping for any keywords, ship-to country and currency, as a clean table or through an API — no login. Use it as an AliExpress scraper for product research, dropshipping sourcing, competitor price monitoring and price-drop alerts.

**No login, no cookies, no personal data:** nothing to sign in to, no cookies to paste, nothing about buyers or sellers in the output.

- **What you get:** one flat row per AliExpress product for any keywords, ship-to (delivery) country, currency and language: price and original price, discount, rating, exact units sold, ship-from country, shipping, Choice badge, listing date, image and link; five filters and a price-monitoring mode that returns only what changed, or only the price drops. No personal data.
- **For whom:** dropshippers and resellers (sourcing), price-tracking and competitive-intelligence tools, market analysts, AI agents through MCP.
- **How much:** from $1.80 per 1,000 products on the Free plan, lower on paid plans; Apify's free monthly credit of $5 covers about 2,777 products. A fixed price per product saved and nothing else (see the Pricing tab); filtered-out products and unchanged prices are never charged; `maxResults` caps every run.

**Sample output**: one real row from a "wireless earbuds" search shipped to the United States, key columns only (the full row is under *Output example*):

```json
{
  "platformProductId": "3256812817428248",
  "title": "2026 New Air 3【 Pro3 】 Bluetooth Wireless Earbuds With Heart Rate Monitoring, Active Noise Cancellation Headphones, Waterproof for Daily Use, For IPhone IOS Smartphone, Gaming /Sports /Fitness Earphones.",
  "currency": "USD",
  "price": 27.29,
  "originalPrice": 64.02,
  "discountPercent": 57,
  "rating": 4,
  "soldCount": 32,
  "shippingFree": true,
  "shipsFrom": "US",
  "isChoice": false,
  "listedAt": "2026-08-20"
}
```

Scrape AliExpress search results for any keywords and get **one flat row per product**: current price and original price, discount, rating, exact number of units sold, ship-from country, free shipping and delivery estimate, main image, AliExpress Choice badge, listing date, sponsored flag and position in the results, for the **ship-to country, currency and language you choose**. **Filter** by minimum rating, units sold, ship-from country, Choice badge or listing date, and **monitor prices**: in price-monitoring mode a scheduled run returns only the new products and the price changes since your previous run, or only the price drops. This AliExpress scraper reads the public search pages without logging in, keeps one browsing session per search, removes duplicates and stops exactly at the number of products you ask for.

**No personal data, by design.** AliExpress search results show no seller, store or buyer, and the scraper keeps it that way: the rows contain product facts only. Store columns stay empty, no review text or reviewer is collected, and every row goes through a privacy filter before it is saved. The dataset is safe to store, share and feed to AI agents.

### What can you do with AliExpress data?

- **Monitor prices and discounts** for a product category across countries and currencies: price tracking, competitive intelligence, deal detection. With `monitorMode` set to `changes`, a daily schedule gives you only the price drops, rises and new arrivals, and you pay only for those rows; add `onlyPriceDrops` for a price-drop alert list.
- **Source products for dropshipping and resale**: exact units sold, ratings, ship-from country (local warehouses vs China), Choice badge and delivery estimates for the destination you sell to; keep only 4.5-star products with 1,000+ orders shipped from your market with the filters.
- **Study a market**: what AliExpress ranks first for a keyword, how many products are sponsored, price distribution, share of local shipping.
- **Feed AI agents, spreadsheets and BI tools** with a stable, documented schema shared by the other scrapers of this e-commerce studio, so products from several marketplaces have the same columns.

### What data does AliExpress Scraper extract?

Every row has every column: a value AliExpress does not show in search results is `null` (or `[]` / `{}` for lists and objects), so CSV and Excel exports keep the same columns from run to run.

| Group | Columns |
|---|---|
| Identity | `schemaVersion`, `platform`, `platformProductId`, `variantId`, `url`, `title`, `brand`, `category`, `categoryPath` |
| Prices | `currency`, `price`, `originalPrice`, `discountPercent`, `inStock`, `stockQuantity` |
| Popularity | `rating`, `ratingMax`, `reviewCount`, `soldCount`, `isBestSeller`, `isChoice`, `listedAt` |
| Seller | `storeType`, `storeName`, `storeId`, `storeUrl`, `storeRating` |
| Shipping | `shippingFree`, `shippingCost`, `deliveryEstimate`, `shipsFrom` |
| Media and attributes | `imageUrl`, `imageCount`, `attributes` |
| Search context | `isSponsored`, `searchQuery`, `searchRank`, `searchPage`, `viewCountryCode`, `scrapedAt` |
| Price monitoring | `changeType`, `previousPrice`, `priceDelta`, `priceDeltaPercent` (null unless `monitorMode` is on, see below) |

Search result cards show a subset of what a product page holds. For this Actor, `brand`, `category`, `categoryPath`, `inStock`, `stockQuantity`, `reviewCount` and `shippingCost` are always empty, `attributes` holds the AliExpress signals that have no column of their own, as text: `soldCountText` (the sales label as displayed, "1,000+ sold"), `shipsTo` (the delivery country), `freeShippingThreshold` (conditional free shipping, see *Shipping, delivery and units sold by country*), `newShopperDeal` and `newShopperSaving` on welcome-deal cards and, in monitoring runs, `priceDirection` (see *Price monitoring*); a key is absent when it does not apply. The seller columns (`storeType` is always `unknown`, `storeName`, `storeId`, `storeUrl`, `storeRating` are always `null`) stay empty by design. `originalPrice` is null when AliExpress shows no strike-through price (European sites show a 30-day lowest price badge instead), `deliveryEstimate` and `shippingFree` only when the card displays them (which depends on the ship-to country), `isBestSeller` only for cards with the "Top selling on AliExpress" badge. `isChoice` is true for cards with the AliExpress Choice badge (about two thirds of the cards in our captures), `listedAt` the date the product was listed, as published on the card (`YYYY-MM-DD`).

### How to scrape AliExpress products

1. **Enter search keywords**, one per line ("wireless earbuds", "bluetooth speaker"), or paste **AliExpress search URLs** copied from your browser, with their category and filters.
2. **Choose the ship-to country, the currency and the language.** AliExpress adapts the catalogue, the prices and the shipping options to the destination, so pick the one your use case needs.
3. **Set the maximum number of products per search**, the sort order (best matches, most ordered, price) and, if needed, the price range, the free-shipping filter and the filters on rating, units sold, ship-from country, Choice badge and listing date.
4. **Run** and open the **Output** tab: the *Overview*, *Prices*, *Ranking* and *Changes* views show the main columns; export everything as JSON, CSV, Excel or through the API.
5. **To follow prices**, schedule the run and set `monitorMode` to `changes` with a `monitorStoreName`: every run after the first returns only what changed (see *Price monitoring* below).

### Input

Give at least one keyword in `searchQueries` or one URL in `startUrls`. Search URLs copied from your browser keep their category and filter parameters; the sort order, price range and filters you set are applied on top, and `searchQueries` can then stay empty. Field names and defaults are those of the input form.

The input of our validation run: the first 60 products for "wireless earbuds" shipped to the United States, prices in USD, titles in English, AliExpress' own order (every other field keeps its default):

```json
{
  "searchQueries": [
    "wireless earbuds"
  ],
  "country": "US",
  "currency": "USD",
  "language": "en",
  "sortBy": "default",
  "maxResults": 60
}
```

Every field, with its type and default:

| Field | Type | Default | Description |
|---|---|---|---|
| `searchQueries` | string\[] | — | Search keywords, one search per entry, as typed in the AliExpress search box. Prefilled with "wireless earbuds". |
| `startUrls` | string\[] | `[]` | AliExpress search result URLs copied from your browser (category and filter parameters kept). Sorting and filters below are applied on top only when set. |
| `maxResults` | integer | `100` | Stop each search after this many unique products. You are never charged for more. Prefilled with 20 in the form. |
| `maxPages` | integer | `100` | Safety cap on result pages read per search (60 products per page). |
| `sortBy` | string | `"default"` | `default` (best matches), `orders` (most ordered), `price_asc` or `price_desc`. AliExpress sorts each page of 60 on its own: exact order within a page, approximate across pages (sort the dataset by `price` for a strict order). |
| `priceMin` | integer | — | Minimum price in the selected currency, a whole number (e.g. 10). |
| `priceMax` | integer | — | Maximum price in the selected currency, a whole number (e.g. 50), at least `priceMin`. |
| `freeShippingOnly` | boolean | `false` | Keep only products AliExpress ships for free to the selected country. |
| `includeSponsored` | boolean | `true` | Keep the sponsored products mixed into the results (flagged in `isSponsored`) or skip them. |
| `minRating` | number | — | Keep only products rated at least this value (0–5, e.g. 4.5). Unrated products are left out. |
| `minSold` | integer | — | Keep only products with at least this many units sold, compared with the exact figure (`soldCount`: "1,000+ sold" can be 1,720). Products without a sales figure are left out. |
| `shipsFrom` | string\[] | `[]` | Keep only products shipped from these countries (ISO codes: US, CN, FR…). Products with an unknown origin are left out. Empty = every origin. |
| `choiceOnly` | boolean | `false` | Keep only products with the AliExpress Choice badge (`isChoice`). |
| `listedWithinDays` | integer | — | Keep only products listed within the last N days (`listedAt`), for new arrivals. Products without a listing date are left out. |
| `country` | string | `"US"` | Ship-to (delivery) country, ISO 3166-1 alpha-2 code (US, GB, FR, DE, BR…). Catalogue, prices, shipping badges and delivery dates follow it. Recorded in `viewCountryCode` and `attributes.shipsTo`. |
| `currency` | string | `"USD"` | Currency for every price, ISO 4217 code (USD, EUR, GBP…). |
| `language` | string | `"en"` | Language of titles and badges: en, fr, es, de, it, pt, nl, pl, ru, uk, tr, ja, ko, th, vi, id, ar, he. |
| `monitorMode` | string | `"off"` | `off`: every product. `changes`: only new products and price changes since your previous run of the same search. `all`: every product with its `changeType`. Compared rows carry `attributes.priceDirection` (`drop`, `rise`, `same`). |
| `monitorStoreName` | string | — | Required when `monitorMode` is on: names the key-value store that keeps the previous prices (`aliexpress-monitor-<name>`, in your account). One name per schedule; letters, digits and dashes. Formerly `monitorKey`, still accepted: same store, same previous prices. |
| `onlyPriceDrops` | boolean | `false` | With `monitorMode` on: write and charge only the products whose price went down since the previous run (a price-drop alert list). The first run records the prices and writes nothing. |
| `proxyConfiguration` | object | `{"useApifyProxy":true}` | Apify datacenter proxies by default, included in the price; keep them, or bring your own proxy URLs. |
| `maxRequests` | integer | `500` | Safety cap on result pages fetched in one run, all searches included. |
| `delayMs` | integer | `800` | Pause between two page requests of the same search, in milliseconds. |
| `debugStoreHtml` | boolean | `false` | Debugging only: store every fetched page in the key-value store. |

### Output example

One real row, produced by the Actor from a "wireless earbuds" search shipped to the United States (USD, English). All columns are present, in this order, for every product:

```json
{
  "schemaVersion": "ecommerce-product/1.1",
  "platform": "aliexpress",
  "platformProductId": "3256812817428248",
  "variantId": "12000060018766532",
  "url": "https://www.aliexpress.com/item/3256812817428248.html",
  "title": "2026 New Air 3【 Pro3 】 Bluetooth Wireless Earbuds With Heart Rate Monitoring, Active Noise Cancellation Headphones, Waterproof for Daily Use, For IPhone IOS Smartphone, Gaming /Sports /Fitness Earphones.",
  "brand": null,
  "category": null,
  "categoryPath": [],
  "currency": "USD",
  "price": 27.29,
  "originalPrice": 64.02,
  "discountPercent": 57,
  "inStock": null,
  "stockQuantity": null,
  "rating": 4,
  "ratingMax": 5,
  "reviewCount": null,
  "soldCount": 32,
  "storeType": "unknown",
  "storeName": null,
  "storeId": null,
  "storeUrl": null,
  "storeRating": null,
  "shippingFree": true,
  "shippingCost": null,
  "deliveryEstimate": null,
  "shipsFrom": "US",
  "imageUrl": "https://ae-pic-a1.aliexpress-media.com/kf/Sb5cfbb9b1c1b480a9f51b0cf05d8cc40e.jpg",
  "imageCount": 1,
  "attributes": {
    "soldCountText": "32 sold",
    "shipsTo": "US"
  },
  "isSponsored": false,
  "isBestSeller": null,
  "isChoice": false,
  "listedAt": "2026-08-20",
  "searchQuery": "wireless earbuds",
  "searchRank": 1,
  "searchPage": 1,
  "viewCountryCode": "US",
  "scrapedAt": "2026-10-19T10:00:00.000Z",
  "changeType": null,
  "previousPrice": null,
  "priceDelta": null,
  "priceDeltaPercent": null
}
```

`price` is the "from" price of the cheapest variant as displayed on the search card, after the discount; `variantId` identifies that variant. `soldCount` is the **exact number of units sold**: AliExpress rounds the label on the card ("900+ sold" on the first French result, kept in `attributes.soldCountText`) but its card data carries the exact figure (981 for that product), which the scraper uses when it agrees with the label. `attributes.shipsTo` repeats the delivery country. The last four columns are filled in price-monitoring runs only.

The **Output** tab offers four views of the same rows: **Overview** (title, price, currency, original price, discount, rating, units sold, ships from, free shipping, sponsored, Choice, link, image), **Prices** (product and variant ids, price, original price, discount, currency, free shipping, delivery estimate, ships from), **Ranking** (query, page, rank, sponsored, best-seller and Choice flags, listing date, units sold, rating, ship-to country) and **Changes** (price-monitoring runs: change type, price, previous price, difference, query, link).

### Shipping, delivery and units sold by country

AliExpress adapts the shipping badges of the search cards to the ship-to country, and shows no shipping fee on them. The scraper reads what the card shows for the country you chose and leaves the rest `null`; `viewCountryCode` and `attributes.shipsTo` carry that country on every row. What our captures of 2026-10-19 contained:

| Ship-to country | Free shipping | Delivery date (`deliveryEstimate`) | Units sold (`soldCount`) |
|---|---|---|---|
| United States (`US`) | `shippingFree` true on about a quarter of the cards (74 of 286), `null` on the others | on more than half of the cards (159 of 286), e.g. "Oct 25 - 30" | exact on every product with a sales label (339 of 339 across all captures) |
| France (`FR`) | every card says it: `shippingFree` true (28 of 60) or `attributes.freeShippingThreshold` = `"10.00"` for "Free shipping over 10€" (32 of 60) | none: French cards show no delivery date, so `deliveryEstimate` is `null` | exact, e.g. 981 behind "900+ sold" |
| Other countries | read the same way when the card shows a badge, `null` otherwise | read when the card shows a date, `null` otherwise | exact when AliExpress has the figure, else the lower bound of the label |

Badges are read in English, French, Spanish, German, Italian, Portuguese and Dutch. `freeShippingThreshold` is the order amount above which shipping is free, in `currency`; `shippingFree` stays `null` on those cards because a single cheap item may not reach it. `RUN_STATS.extra.soldCountsRounded` counts the rows where only the rounded label was available (none in our captures), and the run log warns when they exceed a fifth of the products.

### Filters

AliExpress itself only filters by price range and free shipping (`priceMin`, `priceMax`, `freeShippingOnly`, applied in the search URL). The five filters below are applied by the scraper **after each page is read and before anything is saved**: a product that does not pass them is never saved, never charged and does not count in `maxResults`, so "100 products rated 4.5 or more" gives you 100 such products.

| Filter | Keeps | Leaves out |
|---|---|---|
| `minRating` | products rated at least the value (decimals allowed) | products without a rating yet |
| `minSold` | products with at least that many units sold (exact figure, `soldCount`) | products without a sales figure |
| `shipsFrom` | products shipped from one of the listed countries | products whose origin is not shown |
| `choiceOnly` | products with the AliExpress Choice badge | the others, including cards without any badge |
| `listedWithinDays` | products listed within the last N days (calendar days, today = 0) | products without a listing date |

The run log says how many products each filter removed, and `RUN_STATS.extra` keeps the counters (`filteredOut`, `filteredOutMinRating`, `filteredOutMinSold`, `filteredOutShipsFrom`, `filteredOutChoiceOnly`, `filteredOutListedWithinDays`). Strict filters cost pages: the scraper reads up to `maxPages` pages per search and **stops a search after 5 consecutive pages without a single product passing the filters**, with an explicit log message, instead of reading 100 pages for nothing. A run where no product at all passes the filters ends as failed, like any empty run, so loosen the filters or raise `maxPages` when that happens.

### Price monitoring

Set `monitorMode` to `changes` and give a `monitorStoreName`, then **schedule the run** (daily is typical). The scraper keeps the last price of every product it compared in a key-value store of your account named `aliexpress-monitor-<monitorStoreName>`, with one record per search (same keywords or URL, ship-to country, currency, sort order and filters). The first run of a search is the reference: every product comes back with `changeType` = `"new"` (and `RUN_STATS.monitorBaseline` is true). From the second run on, in mode `changes` the dataset holds **only the new products and the products whose price changed**, with the previous price and the difference, and **only those rows are charged**; a run where nothing changed succeeds with an empty dataset. Mode `all` returns every compared product with its `changeType` (`new`, `price_changed` or `unchanged`). In both modes `maxResults` is the number of products compared per search.

Every compared row also says **which way the price moved** in `attributes.priceDirection`: `drop`, `rise` or `same` (absent on new products and when the currency changed, since there is nothing to compare). Set **`onlyPriceDrops`** to `true` to write and charge **only the drops**, whatever the mode: the dataset of each scheduled run is then a ready-made price-drop alert list, empty on days without a drop. Every compared price is still recorded, rises included, so the next drop is measured from the latest price. `RUN_STATS.monitor` counts `priceDrops` and `priceRises`.

A scheduled input that watches the 100 best-selling wireless earbuds shipped to the United States:

```json
{
  "searchQueries": ["wireless earbuds"],
  "country": "US",
  "currency": "USD",
  "sortBy": "orders",
  "maxResults": 100,
  "monitorMode": "changes",
  "monitorStoreName": "earbuds-daily"
}
```

A `price_changed` row, as the Actor produces it from the row of the output example when the previous run had recorded 29.99 USD (the other columns are the same as above):

```json
{
  "platformProductId": "3256812817428248",
  "title": "2026 New Air 3【 Pro3 】 Bluetooth Wireless Earbuds With Heart Rate Monitoring, Active Noise Cancellation Headphones, Waterproof for Daily Use, For IPhone IOS Smartphone, Gaming /Sports /Fitness Earphones.",
  "currency": "USD",
  "price": 27.29,
  "changeType": "price_changed",
  "previousPrice": 29.99,
  "priceDelta": -2.7,
  "priceDeltaPercent": -9,
  "attributes": {
    "soldCountText": "32 sold",
    "shipsTo": "US",
    "priceDirection": "drop"
  }
}
```

What to know before relying on it:

- **The record is written only after a search that ended cleanly.** A blocked, failed or empty search, a run stopped by its budget or an interrupted run never overwrites the reference, so a bad day cannot erase your prices; the log says when a record was kept unchanged.
- **Same currency only.** A price is compared only with a previous price in the same currency; when AliExpress switches the displayed currency, the product is reported `unchanged` and the new currency becomes the reference.
- **Welcome deals are compared as displayed.** On cards flagged `attributes.newShopperDeal`, `price` is the first-time-buyer price; a card gaining or losing that deal shows up as a price change. Filter those rows out if you track regular prices.
- **Rankings move.** AliExpress reshuffles results between sessions, so the set of compared products (the top `maxResults` of each search) drifts a little from run to run; a product that drops out of the results and comes back later is not reported as new (its last price is kept for 90 days). The catalogue also depends on the ship-to country: one store name per country.
- **One store name per schedule.** Runs sharing a `monitorStoreName` share the records; changing the keywords, country, currency, sort or filters of a search starts a new reference for it. Delete the key-value store in Apify Console to start over.
- **Saved inputs with `monitorKey` keep working.** The field was renamed `monitorStoreName` on 2026-10-20; a task or schedule that still sends `monitorKey` uses the same store, hence the same previous prices, and the log asks you to rename the field.

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

This Actor uses **pay-per-event pricing: you pay a fixed price per product** saved to your dataset, and nothing else. On the Free plan, products cost $1.80 per 1,000, so Apify's free monthly credit of $5 covers about 2,777 products; paid plans pay less per product, and the price of every plan tier is on the **Pricing tab** of this page.

| What you pay for | How it is counted | Price |
|---|---|---|
| `result` event: one product saved to your dataset | once per unique product of the run, capped by `maxResults` | Pricing tab, per plan tier |
| Run start | a symbolic amount, once per run | Pricing tab |
| Compute, proxies, storage and data transfer | included: no platform usage is passed on to you | — |

The cost of a run is known before you start: 1,000 products cost 1,000 times the `result` price of your tier, whatever the number of pages fetched. Products removed by the filters are not charged, and in price-monitoring mode `changes` only the new products and the price changes are charged (only the price drops with `onlyPriceDrops`). A page of 60 products takes a few seconds; a run of a few hundred products takes under a minute.

### Limits and behaviour worth knowing

- **Search results only.** The Actor reads search result cards, not product pages: review counts, stock, variants, attributes and seller details are not available (see the column notes above). Product pages are heavily protected on AliExpress and are out of scope.
- **60 products per page, about 15 of them sponsored.** Sponsored cards are kept and flagged in `isSponsored` by default; set `includeSponsored` to false to skip them. `searchRank` counts every card of the page, sponsored ones included.
- **Rankings move and totals are approximate.** AliExpress reshuffles results between sessions and announces a different total on every page. The scraper keeps one session per search (same proxy session, same cookies and headers), removes duplicates by product id across the whole run, and stops when two consecutive pages bring nothing new, when the announced results are exhausted, or at `maxResults` / `maxPages`. Deeper pages repeat 15–20 % of the products already seen (sponsored cards included): 600 unique products take about 12 pages.
- **The ship-to country changes everything.** The catalogue, the prices, the currency and the shipping options depend on `country`; rows obtained with different countries are not comparable. When AliExpress displays prices in a currency other than the one requested, the rows carry the displayed currency and the run log says so.
- **Prices are "from" prices.** The search card shows the cheapest variant after discount; `originalPrice` and `discountPercent` are the strike-through price and the percentage off as displayed. European sites often show no strike-through price (a 30-day lowest price badge instead).
- **Welcome deals: some prices are for first-time buyers only.** Outside the EU, AliExpress shows visitors "welcome deal" prices on part of the cards (more than half of the rows of a US search in our tests): `price` is then the price a new shopper pays, `originalPrice` the price before that saving, and the row carries `attributes.newShopperDeal` = `"true"` with `attributes.newShopperSaving` (the saving as displayed, in `currency`). Filter on it when you track regular prices. French pages showed no welcome deals.
- **Sorting by price is per page.** With `sortBy` set to `price_asc` or `price_desc`, AliExpress sorts each page of 60 separately and pages overlap, so the order is exact within a page and only approximate across pages; price-sorted pages carried no sponsored cards. Sort the dataset by `price` for a strict order.
- **Promo cards without a price are skipped.** Cards that advertise a free gift for new shoppers show no price: they are not saved and not charged; the run log and `RUN_STATS.extra.productsWithoutPrice` count them.
- **Shipping details depend on the ship-to country.** AliExpress prints a delivery date on US cards but not on French ones, and French cards show "Free shipping over 10€" where US cards show nothing: `deliveryEstimate` and `shippingFree` are null where the site shows nothing (see *Shipping, delivery and units sold by country*).
- **Blocking.** AliExpress search pages are served to Apify datacenter proxies without challenge in our tests. If a page is unusable, the scraper opens a new session and retries once, then gives up on that search and reports it in the log. If a whole run is blocked, raise `delayMs` and try again later, or open an issue with your run id: blocking changes are fixed as a priority.
- **No empty successes.** A run that finds no product ends as failed with an explicit message (keywords misspelt, filters too strict, or blocked), so that your schedules and integrations notice. The one exception is a price-monitoring run that compared products and found no change: it succeeds with an empty dataset.

### Integrations and API

Start the Actor from Apify Console, schedule it, or call it from the [Apify API](https://docs.apify.com/api/v2) with any language (the **API** tab shows ready-made code for Node.js, Python and curl). Webhooks notify your systems when a run finishes; the dataset can be pulled as JSON, CSV, Excel, XML or RSS, or pushed to Google Sheets, Make, Zapier, n8n, Slack, Airtable, Google Drive and more through the Apify integrations.

### Use it from your AI assistant

Add this Actor as a tool to Claude, ChatGPT, Cursor, VS Code or any MCP client with the Apify MCP server URL below (sign in with your Apify account when asked):

`https://mcp.apify.com?tools=myth84/aliexpress-search-scraper`

Then ask in plain words. Copy this prompt and change the details:

```text
Use myth84/aliexpress-search-scraper to find the 30 best-selling wireless earbuds on AliExpress delivered to France, prices in EUR. Input: {"searchQueries": ["wireless earbuds"], "country": "FR", "currency": "EUR", "sortBy": "orders", "maxResults": 30}. Show the title, price, original price, discount, rating, units sold, ship-from country and link of each product.
```

### For AI agents (MCP)

Through the [Apify MCP server](https://docs.apify.com/mcp) this Actor is a tool that answers questions such as *"what do wireless earbuds cost on AliExpress when shipped to France, in euros?"* or *"find the best-selling bluetooth speakers under 30 dollars that ship from the United States"*.

**Minimal input** (every other field keeps its default; raise `maxResults` only when the question needs more rows):

```json
{
  "searchQueries": [
    "bluetooth speaker"
  ],
  "country": "FR",
  "currency": "EUR",
  "maxResults": 20
}
```

- **Key output fields**: `platformProductId`, `title`, `url`, `price`, `originalPrice`, `discountPercent`, `currency`, `rating`, `soldCount` (exact units sold), `shipsFrom`, `shippingFree`, `deliveryEstimate`, `isChoice`, `imageUrl`, `viewCountryCode` (delivery country); in monitoring mode `changeType`, `previousPrice`, `priceDelta` and `attributes.priceDirection` (`drop`, `rise`, `same`). Every column is always present, in a fixed order; `null` means AliExpress did not show the value. The full list is in *What data does AliExpress Scraper extract?* above.
- **Use it when** you need current AliExpress search results for keywords: prices, discounts, ratings, units sold, ship-from country, Choice badge, images. Pass `searchQueries` (or `startUrls`), `country`, `currency`, `language`, optionally `sortBy`, `priceMin` / `priceMax`, `freeShippingOnly`, the filters `minRating`, `minSold`, `shipsFrom`, `choiceOnly`, `listedWithinDays`, and a small `maxResults` (20–60 is enough for an answer). To report price changes between two calls, pass `monitorMode: "changes"` and a stable `monitorStoreName`; add `onlyPriceDrops: true` to get only the products whose price went down.
- **Do not use it for** product pages, reviews, stock, variants, seller information or anything behind a login: it only reads public search results and collects no personal data.
- **Cost per 1,000 results**: 1,000 `result` events, $1.80 per 1,000 on the Free plan and less on paid plans (Pricing tab); nothing else is charged (filtered-out products and, in monitoring mode, unchanged prices are free).
- **Typical time**: a few seconds per page of 60 products: 20 products in under ten seconds, a few hundred in under a minute.

### Alternatives and switching

- **Official API.** AliExpress's official APIs belong to its affiliate and seller programmes and need an approved account and app keys. This Actor reads what any visitor sees in AliExpress search results (public prices, discounts, units sold, shipping for your delivery country) with no account, no keys and no approval.
- **Your own scraper.** Nothing to build or maintain: sessions, retries, pagination, deduplication and AliExpress page changes are handled for you. The columns stay the same from run to run, a run that finds nothing fails with an explicit message instead of succeeding empty, and a scheduled test run catches AliExpress changes early.
- **Another scraper from the Store.** The input names differ from one Actor to the next; the usual ones map to this Actor as follows:

| Usual input | Here | Note |
|---|---|---|
| `search`, `query`, `keyword` | `searchQueries` | Several keywords per run |
| `startUrls` | `startUrls` | AliExpress search URLs |
| `maxItems`, `limit` | `maxResults` | Unique products per search, never charged beyond |
| `shipTo`, `country` | `country` | Delivery country: prices, shipping and delivery follow it |
| `currency`, `language` | `currency`, `language` | ISO 4217 code, AliExpress language |
| `minPrice`, `maxPrice` | `priceMin`, `priceMax` | In `currency` |
| `sort` | `sortBy` | `default`, `orders`, `price_asc`, `price_desc` |
| `proxy` | `proxyConfiguration` | Apify proxies, included in the price |

### FAQ

#### Does AliExpress Scraper collect personal data?

No. Search result cards show no seller, store or buyer, and the scraper outputs product facts only: prices, discount, rating, units sold, shipping, image, position in the results. Store columns are always empty and every row goes through a privacy filter before it is saved.

#### Is it legal to scrape AliExpress?

The Actor only reads pages that AliExpress serves to any visitor without an account, and it stores no personal data. Scraping public data is generally lawful, but you are responsible for how you use the results and for complying with AliExpress' terms of use and the laws that apply to you (including copyright on product texts and images). Use the data for analysis, not to republish listings.

#### What if my runs get blocked? Do I need proxies?

Apify datacenter proxies (the default) work for AliExpress search pages and are included in the price. If a run reports blocked pages, increase `delayMs` and try again later, or bring your own proxy URLs; persistent blocking is fixed as a priority, open an issue with your run id.

#### Why do I get fewer products than AliExpress announces, or the same product twice across runs?

AliExpress announces thousands of results but the usable depth of a search is smaller, and its ranking changes between sessions: the scraper removes duplicates within a run by product id, which is why a page may yield fewer than 60 new products, and stops when two pages bring nothing new. Deeper pages also repeat 15–20 % of the products already seen. Across separate runs, use `platformProductId` to deduplicate.

#### Which countries, currencies and languages are supported?

Any ship-to country AliExpress delivers to (`country`, ISO code), any currency it displays (`currency`) and 18 interface languages (`language`). Prices, catalogue and shipping follow the ship-to country; if AliExpress ignores the requested currency for a country, the rows carry the currency actually displayed.

#### What are the sponsored, best-seller and Choice badges, and how do I find new arrivals?

AliExpress mixes about 15 sponsored cards into each page of 60; they are flagged in `isSponsored` and can be skipped with `includeSponsored`. `isBestSeller` is true for cards carrying the "Top selling on AliExpress" badge. `isChoice` is true for products in the AliExpress Choice programme (platform-curated offers with combined shipping and free returns); set `choiceOnly` to keep only those. `listedAt` is the date the product was listed, as shown on the card; `listedWithinDays` keeps only products listed within the last N days.

#### What do `price`, `originalPrice` and `discountPercent` mean?

`price` is the current price of the cheapest variant as shown on the search card ("from" price, after discount), `originalPrice` the strike-through price when AliExpress shows one, and `discountPercent` the percentage off as displayed. All three are in `currency` for the ship-to country. On rows flagged `attributes.newShopperDeal`, `price` is the welcome-deal price AliExpress offers first-time buyers and `originalPrice` the price before that saving.

#### How often should I run it, and how do I get only price changes?

Every run fetches live search results. Prices, discounts and rankings change daily, so schedule the Actor as often as your use case needs (daily is typical for price tracking) and compare runs by `platformProductId`, `country` and `currency`, or let the Actor compare them for you: set `monitorMode` to `changes`, choose a `monitorStoreName` (for example `earbuds-daily`) and schedule the run. The first run records every product of the search and returns it as `new`; each later run returns only the products that appeared since and the products whose price changed, with `previousPrice`, `priceDelta` and `priceDeltaPercent`, and charges only those rows. A run without any change succeeds with an empty dataset. The previous prices live in the key-value store `aliexpress-monitor-<monitorStoreName>` of your account; keep the same keywords, country, currency, sort and filters from run to run, and use one store name per schedule. Use `monitorMode` = `all` to get every product with its `changeType`.

#### How do I get alerted when prices drop?

Turn on price monitoring with `onlyPriceDrops` and schedule the run. With this input, each run returns, and charges, only the products whose price went down since the previous run, each with `previousPrice`, `priceDelta`, `priceDeltaPercent` and `attributes.priceDirection` = `drop`:

```json
{
  "searchQueries": ["wireless earbuds"],
  "country": "FR",
  "currency": "EUR",
  "sortBy": "orders",
  "maxResults": 100,
  "monitorMode": "changes",
  "monitorStoreName": "earbuds-fr-drops",
  "onlyPriceDrops": true
}
```

Save it as a task, then add a daily schedule in Apify Console (**Schedules**). The first run records the prices and writes nothing; from the second run on, a non-empty dataset is your alert, and a day without a drop succeeds with an empty dataset. To be notified, connect the task to e-mail, Slack, Google Sheets or a webhook through the **Integrations** tab of the task.

#### How do I export or integrate the results, and where do I get support?

From the run's Output tab (JSON, CSV, Excel, XML, RSS) or automatically: Apify API, webhooks, scheduled runs and integrations with Google Sheets, Make, Zapier, n8n, Slack and others; AI agents can call the Actor through the Apify MCP server. For bugs or questions, open an issue in the **Issues** tab of this Actor with your run id and input: page-layout changes are fixed as a priority, feature requests (other marketplaces of the studio) are welcome.

### More scrapers by Flatrow Data Studio

The e-commerce scrapers of the studio share the same columns, so products from several marketplaces land in one comparable table:

- [eBay Listings Scraper & Price Tracker](https://apify.com/myth84/ebay-search-scraper): eBay prices, condition, shipping and units sold on 9 marketplaces, with price monitoring.
- [Etsy Listings Scraper & Price Tracker](https://apify.com/myth84/etsy-search-scraper): Etsy prices, sale prices, ratings and review counts for any common search term, with price monitoring.

Did this scraper give you the data you needed? A rating on its Store page helps other people find it. For a bug or a missing field, open an issue in the **Issues** tab.

### Legal note

This Actor reads publicly available AliExpress search pages without logging in and collects no personal data. You are responsible for your use of the data and for complying with AliExpress' terms and the laws that apply to you.

Not affiliated with, endorsed or sponsored by AliExpress or Alibaba. AliExpress is a trademark of Alibaba Group.

# Changelog

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

# Actor input Schema

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

Enter one search per line, as you would type it in the AliExpress search box, e.g. <code>wireless earbuds</code> or <code>bluetooth speaker</code>. Each search gets its own results, up to the maximum number of products below. No default: give keywords here or search URLs below (the form is prefilled with wireless earbuds).

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

Paste one or more AliExpress search result URLs copied from your browser (<code>https://www.aliexpress.com/w/wholesale-....html?SearchText=...</code>); their category and filter parameters are kept. The sorting and filters below are applied on top only when you set them. Default empty: keywords are enough for most searches.

## `maxResults` (type: `integer`):

Stop each search (keyword or URL) after this many unique products; you are never charged for more. A result page holds 60 products. Default 100: the top of a market in two pages; 20 to 60 is enough for a quick answer (the form is prefilled with 20 for a quick first run).

## `maxPages` (type: `integer`):

Safety cap on the number of result pages read for one search (60 products per page). The scraper also stops when two consecutive pages bring no new product. Default 100: high enough never to stop a search before maxResults.

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

Order of the results, as offered by the AliExpress sort bar: best matches, most ordered, price from low to high, price from high to low. AliExpress sorts each page of 60 on its own: the order is exact within a page and approximate across pages. Default: best matches, the order a shopper sees.

## `priceMin` (type: `integer`):

Keep only products priced at least this amount, a whole number in the selected currency, e.g. <code>10</code> for 10 USD; sent to AliExpress as its own price filter. Leave empty for no minimum.

## `priceMax` (type: `integer`):

Keep only products priced at most this amount, a whole number in the selected currency, e.g. <code>50</code> for 50 USD; sent to AliExpress as its own price filter; it must be at least priceMin. Leave empty for no maximum.

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

Keep only products that AliExpress ships for free to the selected country (the site's own filter). Default false: every product, with free shipping reported in shippingFree and conditional offers in attributes.freeShippingThreshold.

## `includeSponsored` (type: `boolean`):

AliExpress mixes about 15 sponsored products into each page of 60. Keep them (they are flagged in the isSponsored column) or skip them. Default true: they are real offers, and the ranks stay those shown on the site.

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

Keep only products rated at least this value (0 to 5, decimals allowed, e.g. 4.5). Products without a rating yet are left out. Leave empty for no minimum.

## `minSold` (type: `integer`):

Keep only products with at least this many units sold, compared with the exact figure behind AliExpress' rounded label (soldCount: "1,000+ sold" can be 1,720). Products without a sales figure are left out. Leave empty for no minimum.

## `shipsFrom` (type: `array`):

Keep only products shipped from these countries (ISO 3166-1 alpha-2 codes, one per line: <code>US</code>, <code>CN</code>, <code>FR</code>…). Products with an unknown origin are left out. Default empty: every origin.

## `choiceOnly` (type: `boolean`):

Keep only products with the AliExpress Choice badge (platform-curated offers with combined shipping and free returns), reported in the isChoice column. Default false: every product.

## `listedWithinDays` (type: `integer`):

Keep only products listed on AliExpress within this many days (new arrivals), from the listing date shown on the card (listedAt column). Products without a listing date are left out. Leave empty for no limit.

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

ISO 3166-1 alpha-2 code of the delivery (ship-to) country: US, FR, DE, GB, BR… AliExpress adapts the catalogue, prices, shipping badges and delivery dates to it. Pick one from the list or type any code; recorded in viewCountryCode and attributes.shipsTo. Default US: the largest catalogue; use FR for deliveries to France.

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

ISO 4217 code of the currency for every price (USD, EUR, GBP…). Pick one from the list or type any code AliExpress supports. If AliExpress ignores the request for a country, the rows carry the currency actually displayed. Default USD: pair it with the country (EUR for FR, GBP for GB).

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

Language of the product titles and badges. Default en: English titles whatever the ship-to country, easiest to compare.

## `monitorMode` (type: `string`):

Off: every product is returned. Changes: only new products and price changes since the previous run of the same search are returned and charged; a run without any change succeeds with an empty dataset. All: every product with its changeType (new, price_changed, unchanged). attributes.priceDirection tells drop, rise or same. maxResults is the number of products compared per search. Default off: a plain search.

## `monitorStoreName` (type: `string`):

Required when price monitoring is on: names the key-value store of your account that keeps the previous prices (aliexpress-monitor-\<name>). Use one name per schedule, e.g. <code>earbuds-daily</code>. Letters, digits and dashes only, at most 44 characters; upper case is lowered. No default: leave empty when monitoring is off.

## `onlyPriceDrops` (type: `boolean`):

Write and charge only the products whose price went down since the previous run of the same search (attributes.priceDirection = drop): a ready-made price-drop alert for a daily schedule. Needs monitorMode changes or all and a monitorStoreName; the first run records the prices and writes nothing. Default false: new products and price rises are returned too.

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

Apify datacenter proxies (automatic) are enough for AliExpress search pages. If your runs get blocked, switch to Apify residential proxies. You can also provide your own proxy URLs. Default: Apify datacenter proxies, included in the price.

## `maxRequests` (type: `integer`):

Safety cap on the number of result pages fetched in one run, all searches included (60 products per page). Default 500: about 30,000 products, far above a usual run.

## `delayMs` (type: `integer`):

Pause between two page requests of the same search, in milliseconds. Increase it if you get blocked; 0 disables the pause. Default 800: polite pacing that keeps a page of 60 products to a few seconds.

## `debugStoreHtml` (type: `boolean`):

Debugging only: save every fetched page in the run's key-value store. Slows the run down and uses storage. Default false.

## Actor input object example

```json
{
  "searchQueries": [
    "wireless earbuds"
  ],
  "startUrls": [],
  "maxResults": 20,
  "maxPages": 100,
  "sortBy": "default",
  "freeShippingOnly": false,
  "includeSponsored": true,
  "shipsFrom": [],
  "choiceOnly": false,
  "country": "US",
  "currency": "USD",
  "language": "en",
  "monitorMode": "off",
  "onlyPriceDrops": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxRequests": 500,
  "delayMs": 800,
  "debugStoreHtml": false
}
```

# Actor output Schema

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

All extracted products as dataset items, one flat row per product. Append ?format=csv or ?format=xlsx for spreadsheets. The Overview view is selected by default; the Changes view shows price-monitoring results.

## `runStats` (type: `string`):

Requests made, bytes transferred, blocked pages, products seen (sponsored included), filtered out and pushed, rows with a rounded sales figure only, price-monitoring counters (price drops and rises included), and the estimated platform cost of the run.

# 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 = {
    "searchQueries": [
        "wireless earbuds"
    ],
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("myth84/aliexpress-search-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 = {
    "searchQueries": ["wireless earbuds"],
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("myth84/aliexpress-search-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 '{
  "searchQueries": [
    "wireless earbuds"
  ],
  "maxResults": 20
}' |
apify call myth84/aliexpress-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,myth84/aliexpress-search-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/cuPvsrxB0bpmqhmV0/builds/iCFcFgptxz0gqCQUg/openapi.json
