# AliExpress Scraper & Price Monitor - Prices, Discounts, Sold (`neverempty/aliexpress-search-price-monitor`) Actor

AliExpress search results by keyword: price, original price, discount, rating, units sold, ship-from and delivery. Flags new-shopper prices and checks the currency. Monitor mode returns only new products and price drops. No login. Export as JSON, CSV or Excel. Unofficial.

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

## Pricing

from $4.50 / 1,000 product returneds

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 Scraper & Price Monitor - Prices, Discounts, Sold

Get products from **AliExpress** search results by keyword: title, **price, original price and discount**, currency, rating, **units sold**, ship-from country, delivery estimate, Choice and sponsored flags, image and link. **Monitor mode** returns only products that are new in the results and **price drops** since the last check, so it can run on a schedule and send you only what changed.

Unofficial. Reads public search pages only, without logging in. Not affiliated with AliExpress or Alibaba.

### What makes this one different

- **New-shopper prices are flagged.** Visitors who are not logged in often see AliExpress welcome prices ($0.33 Dollar Express, $1.09 welcome deals, "free with any purchase"). AliExpress's own page says that price is for new shoppers. Every row says so in `newShopperOffer` and `priceNote`, instead of passing it off as the regular price.
- **No fake price drops.** In our tests the promotional price of the same product changed from one request to the next ($1.09 then $0.99; $0.33 then $2.34), and the same product was shown with a new-shopper price on one request and its regular price on the next. Monitor mode only compares prices of the same kind: regular price with regular price, or, for two promotional prices, the original (crossed-out) prices. `priceChangeBasis` says which. In the same tests, regular prices read by this Actor matched an independent request of the same page in 52 of 52 products.
- **The currency is checked.** You choose the currency and ship-to country. Every price is checked against the currency you asked for. If AliExpress answers in another currency, you get a free row saying so, not mislabelled prices.
- **Unrelated results are not sold as matches.** For a word AliExpress does not know, it fills the page with unrelated products. When no title on the first page contains any of your search words, the search returns a free `no-results` row. Each product also has `titleMatchesSearch`, and `onlyMatchingTitles` leaves loose matches out.
- **The count you ask for is the count you get**, up to 300 per search (60 per page, up to 5 pages). If there were more results than you got, a free row says so.
- **Every product row has a price.** By default (`onlyPricedProducts`), the Actor leaves out the "free with any purchase" gift cards that AliExpress shows new shoppers without a price, and reads up to two more results pages to fill your list with priced products. In our test of the example search, that gave 60 products, all with a price.

### Output fields

| Field | What it is |
|---|---|
| `itemId`, `url` | AliExpress item ID and product page (`https://www.aliexpress.com/item/<itemId>.html`) |
| `title` | Product title |
| `price`, `currency` | Price shown on the search page, in the currency you asked for |
| `originalPrice`, `discountPercent` | Crossed-out price and the discount AliExpress shows |
| `newShopperOffer`, `platformSubsidy`, `priceNote`, `promotion` | Whether the shown price is a new-shopper or subsidised price, in plain words |
| `rating` | Star rating on the card |
| `soldText`, `soldCountMin`, `tradeCount` | Units-sold label ("10,000+ sold"), its number (a lower bound), and AliExpress's own count behind it |
| `isChoice`, `sponsored` | AliExpress Choice product; advertised placement |
| `shipFrom`, `deliveryText`, `freeShipping` | Ship-from country, delivery estimate, free-shipping label |
| `tags`, `categoryId`, `launchDate`, `imageUrl` | Other labels, category ID, listing launch date, main image |
| `titleMatchesSearch`, `searchUnderstoodAs` | Whether the title contains every search word, and the search words as AliExpress understood them (translated to English for other languages) |
| `page`, `positionOnPage`, `resultsInSearch` | Where the product was, and the result count AliExpress shows |
| `changeType`, `previousPrice`, `priceChange`, `priceChangePercent`, `priceChangeBasis` | Monitor mode only |
| `charged` | `true` when the product row was charged. **Product rows without a price are not charged** (`charged: false`) |
| `status`, `note` | `ok` for product rows; otherwise a free row that says why nothing was returned |

### Input

| Field | What it does |
|---|---|
| `searchQueries` | Search terms, for example `phone case`, `usb c cable`. Other languages work (AliExpress translates them). Empty together with `searchUrls` = example search `phone case` |
| `searchUrls` | AliExpress search pages copied from your browser (`https://www.aliexpress.com/w/wholesale-….html`). The search words and sort order are used; other URL filters are not |
| `sort` | `best-match`, `orders` (most sold first), `price-asc`, `price-desc`. Empty = best match, or orders in monitor mode |
| `currency`, `shipToCountry` | Currency and two-letter ship-to country (default USD and US) |
| `maxResultsPerSearch` | Most products per search, 1 to 300 (default 60) |
| `maxPages` | Pages per search, 1 to 5 (default: just enough for `maxResultsPerSearch`) |
| `includeSponsored` | Return advertised placements too (default on), marked `sponsored` |
| `onlyMatchingTitles` | Leave out products whose title lacks a search word (default off) |
| `onlyPricedProducts` | Leave out products shown without a price (default on). A normal search fills the list from up to two more pages; monitor mode does not (see below). Off = return them too, not charged |
| `onlyNew` | Monitor mode: only new products and price changes |
| `priceChangeAlerts` | Monitor mode: `drops` (default), `any` or `off` |
| `watchName` | Separate monitor memories, for example one per client |
| `resetMonitoringState` | Forget what this watch has seen and start again |

Up to 10 searches per run (search terms plus URLs).

### Monitor mode

1. First run: returns up to `maxResultsPerSearch` products (`first-check`) and remembers the list.
2. Next runs: read the same pages and return only
   - `new-in-results`: a product this watch has not seen in these results before. It may be newly listed, or it may have moved into the pages read. The listing launch date is in `launchDate`; this Actor does not invent a "new since" date.
   - `price-change`: a price drop (or any change, with `priceChangeAlerts: any`), with `previousPrice`, `priceChange`, `priceChangePercent` and `priceChangeBasis`.
3. If a page cannot be read, the watch judges nothing for that search: nothing is returned, remembered or charged, and the next run checks again.
4. If a run reaches your maximum charge, the products it could not return are returned by the next run.
5. Products shown without a price are left out (`onlyPricedProducts`), and monitor mode does not read extra pages to replace them: every run reads the same pages, so products that only moved between pages are not reported as new. The first check says how many were left out.

Use the **orders** sort for a watch (the default in monitor mode). In our tests, three requests of the same **best match** page shared only 24 of 99 products, while three requests of the **orders** page shared 58 to 59 of 60. A best-match watch would report reshuffled products as new.

Even the orders list moves a little: in a test watch on `phone case` run five times within a minute, runs 2 to 5 returned 1, 3, 1 and 0 `new-in-results` products (products that moved into the first 60). Each product is returned as new only once per watch, so this settles as the watch remembers the list.

### Pricing

Pay per event:

- **Run start**: one small fee per run (not per page and not per GB of memory).
- **Product returned**: per product row **with a price**. By default every product row has a price. With `onlyPricedProducts` off, products shown without a price (for example a "free with any purchase" gift for new shoppers) are also returned, with `charged: false`, and are **not charged**. The run log says how many rows were charged and how many were not.

Explanation rows are free. A normal search that finds nothing, or only products without a price, is not charged at all. In monitor mode, the run start fee is the price of the check itself, so it is charged even when nothing changed. Set a maximum charge per run and the Actor will not start a run that cannot return at least one product.

### Reliability

- Reads the plain search page; no browser, no login. Measured 2026-10-09 from Apify's datacenter proxies: every search page request answered (30 of 30), no check page.
- If AliExpress refuses an IP address (403, 429, 5xx), the Actor asks again from other datacenter IPs.
- If AliExpress shows its check page (slide-to-verify), the Actor **does not solve or bypass it**: it stops, returns a free row and remembers nothing.
- AliExpress's robots.txt is checked on every run and every URL is checked against it before it is requested. Only search pages (`/w/wholesale-….html`) are read; product pages are not opened.
- Some products are shown to new shoppers as a "free with any purchase" gift, with no price on the search page (seen with ship-to US). The product page loads its price from an AliExpress service whose robots.txt disallows automated access, so this Actor leaves that price empty instead of guessing it, and does not charge for the row. `onlyPricedProducts` (on by default) leaves such rows out.
- Prices are the ones AliExpress shows to a visitor who is not logged in, for the currency and country you choose. Logged-in shoppers, coupons and coins can change the final price. Promotional prices (new-shopper and Dollar Express) differ between requests, so two runs a minute apart can show different promotional prices for the same product; regular prices do not.

### Example output

```json
{
  "status": "ok",
  "itemId": "1005010439419248",
  "title": "Magnetic Original Clear Case For iPhone 17 16 15 14 Plus 13 12 Mini 11 Pro Max 16E 17E Funda For Magsafe Transparent Cover",
  "price": 0.33,
  "currency": "USD",
  "originalPrice": 3.2,
  "discountPercent": 89,
  "newShopperOffer": true,
  "priceNote": "Price for new AliExpress shoppers (shown to visitors who are not logged in); returning shoppers may pay more.",
  "promotion": "Dollar Express",
  "rating": 4.9,
  "soldText": "50,000+ sold",
  "soldCountMin": 50000,
  "tradeCount": 59773,
  "isChoice": true,
  "sponsored": false,
  "shipFrom": "CN",
  "deliveryText": "Delivery: Oct 16 - 20",
  "titleMatchesSearch": true,
  "url": "https://www.aliexpress.com/item/1005010439419248.html",
  "page": 1,
  "positionOnPage": 1,
  "searchQuery": "phone case"
}
```

### Thanks for using this Actor

We build these tools for people who run them every day, and we improve them from what users tell us.

- **Missing a field, or need another filter?** Tell us in the **Issues** tab. If the data is there, we add it.
- **Found a bug or a wrong value?** Post the run ID in the **Issues** tab. Wrong data is the thing we fix first.

If this Actor saved you time, a short review helps other people find it.

# Actor input Schema

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

What you would type into the AliExpress search box, for example phone case, usb c cable, anker 737 power bank. Other languages work too (AliExpress translates them). Leave Search terms and Search URLs both empty to run the example search phone case.

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

Optional. AliExpress search pages copied from your browser, for example https://www.aliexpress.com/w/wholesale-phone-case.html?SortType=total_tranpro_desc. The search words and the sort order are used; other filters in the URL are not (the run log says which were ignored).

## `sort` (type: `string`):

Sort order for every search (overrides the order in a pasted URL). Empty = Best match for a normal run and Orders in monitor mode. Best match reshuffles about half of the page on every request, so Orders is the steadier list to watch.

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

Currency AliExpress shows the prices in (its own currency setting). Every price is checked: if AliExpress answers in another currency, that search returns a free row saying so instead of mislabelled prices. Empty = USD.

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

Two-letter country code AliExpress uses for prices, delivery dates and availability, for example US, DE, GB, FR. Empty = US.

## `maxResultsPerSearch` (type: `integer`):

Most products returned for one search (AliExpress shows 60 per page). Empty = 60. In monitor mode it limits the products returned per search in one run; the rest come in the next run.

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

How many results pages (60 products each) to read for each search, 1 to 5. Empty = just enough pages for Max products per search. In monitor mode every run reads this many pages and compares them.

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

On (default): return AliExpress's advertised placements too, marked sponsored true. Off: leave them out.

## `onlyMatchingTitles` (type: `boolean`):

On: leave out products whose title does not contain every search word (AliExpress also shows loosely related products). Off (default): return them all, each marked titleMatchesSearch true or false.

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

On (default): leave out products that AliExpress shows without a price (the "free with any purchase" gifts for new shoppers), so every product row has a price. In a normal search the Actor reads up to two more results pages to fill your list with priced products. In monitor mode it reads the same pages every run and does not fill the gap, so products moving between pages are not reported as new. Off: return them too, with price empty and charged false (not charged).

## `onlyNew` (type: `boolean`):

On: every run reads the same pages of each search and returns only products that appear in these results for the first time (changeType new-in-results) and products whose price changed as set in Price change alerts (changeType price-change, with previousPrice). The first run returns up to Max products per search (changeType first-check) and remembers them as the starting point. Each run that reads the list is charged the run start fee; runs where nothing changed return a free row saying so.

## `priceChangeAlerts` (type: `string`):

Which price changes monitor mode returns. New-shopper prices (the welcome prices AliExpress shows to visitors who are not logged in) change from one request to the next, so they are never compared; see priceChangeBasis in the output. Empty = price drops only.

## `watchName` (type: `string`):

Optional. Keeps separate memories for monitor mode, for example one per client (letters, digits, dot, dash, underscore; up to 40). Runs with the same watch name, search, currency and country share what has already been returned.

## `resetMonitoringState` (type: `boolean`):

On: forget what this watch has seen for these searches before running, so this run is a first check again. Off or empty: keep the memory.

## Actor input object example

```json
{
  "searchQueries": [
    "phone case"
  ],
  "currency": "USD",
  "shipToCountry": "US",
  "includeSponsored": true,
  "onlyMatchingTitles": false,
  "onlyPricedProducts": true,
  "priceChangeAlerts": "drops"
}
```

# Actor output Schema

## `results` (type: `string`):

One row per AliExpress product in the search results: item ID, title, price, original price and discount, currency, new-shopper price flag, rating, units sold, ship-from, delivery text, sponsored flag, link, page and position. Monitor mode marks rows first-check, new-in-results or price-change (with the previous price). A search with no products, nothing changed, a check page, a refused request, a currency mismatch or a run that hit its maximum charge comes back as a free row that says why.

# 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": [
        "phone case"
    ],
    "onlyPricedProducts": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/aliexpress-search-price-monitor").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": ["phone case"],
    "onlyPricedProducts": True,
}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/aliexpress-search-price-monitor").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": [
    "phone case"
  ],
  "onlyPricedProducts": true
}' |
apify call neverempty/aliexpress-search-price-monitor --silent --output-dataset

```

## MCP server setup

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

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/8lcw4N4sftN2tT85L/builds/ASaJQ0KN2amMeScV0/openapi.json
