# AliExpress Product Research (`apt_marble/aliexpress-product-research`) Actor

Find what to sell on AliExpress using published numbers only: exact units sold, units sold per day since launch, rating, review volume, discount and local stock. Ranked shortlist, deduplicated, with every figure and weight shown. No estimated revenue, no invented scores.

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

## Pricing

from $0.60 / 1,000 product scoreds

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?

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

## AliExpress Product Research

Pick what to sell using numbers AliExpress publishes, not numbers somebody guessed. Give this actor a few product ideas and it builds a ranked shortlist: how many units each product has actually sold, how many it sells **per day since the day it was listed**, its rating, how many reviews are behind that rating, its price and discount, whether it carries the Choice badge, and which country it ships from. Every figure is shown, every weight is shown, and the working behind each score is written onto the row — so you can trust it, argue with it, or re-rank it yourself in a spreadsheet.

There is no estimated monthly revenue in this output. There is no invented competition index. Both are guesses dressed up as data, and this actor does not make them.

### What you can do with it

- **Find products with real momentum.** Units sold per day since launch separates a product that sold 20,000 units in four months from one that took six years to get there. Most product-research tools cannot tell them apart, because they only see a rounded "10,000+ sold" badge.
- **Shortlist for a dropshipping store** by demanding a minimum sales record, a minimum rating and a local warehouse, then rank what survives.
- **Spot rising products early** with the "Rising fast" weighting: high sales per day, recently listed, before the category fills up.
- **Find the quieter corners** with "Low competition": strongly rated products that have not yet accumulated a huge sales and review history.
- **Compare countries properly.** Choose the country you sell into and you get that country's catalogue, that country's prices in that country's currency, and a clear flag on every product that ships from inside it.
- **Build your own ranking.** Supply your own weights over the same published figures and the actor ranks to your brief instead of ours.

### What you get

One row per product, best first. Abridged real example:

```json
{
  "rank": 1,
  "score": 65.4,
  "scoreOnPublishedMeasures": 77.0,
  "scoreCoverage": 85.0,
  "scorePreset": "proven_sellers",
  "productId": "3256811824694970",
  "globalProductId": "1005012011009722",
  "title": "TWS Bluetooth Earphones Wireless Sports Gaming Earbuds",
  "url": "https://www.aliexpress.com/item/3256811824694970…",
  "unitsSold": 87286,
  "unitsSoldText": "50,000+ sold",
  "salesVelocityPerDay": 752.466,
  "launchDate": "2026-04-16",
  "daysSinceLaunch": 116,
  "rating": 4.9,
  "reviewCount": 3573,
  "price": 4.02,
  "originalPrice": 8.2,
  "currency": "USD",
  "discountPercent": 51,
  "priceIsNewShopperPromo": true,
  "isChoice": true,
  "isPromoted": false,
  "shipFromCountry": "CN",
  "shipsFromSelectedCountry": false,
  "categoryIds": ["44", "100000306", "63705"],
  "foundVia": ["keyword"],
  "foundIn": "wireless earbuds (orders)",
  "scoreWeights": {
    "unitsSold": 30, "salesVelocityPerDay": 25, "rating": 20,
    "reviewCount": 15, "isChoice": 5, "shipsFromSelectedCountry": 5
  },
  "scoreComponents": [
    { "component": "unitsSold", "label": "Units sold since launch", "value": 87286,
      "betterWhen": "higher", "weight": 30, "position": 72.2, "contribution": 21.66 },
    { "component": "salesVelocityPerDay", "label": "Units sold per day since launch",
      "value": 752.466, "betterWhen": "higher", "weight": 25, "position": 90, "contribution": 22.5 },
    { "component": "rating", "label": "Buyer rating", "value": 4.9,
      "betterWhen": "higher", "weight": 20, "position": 81.3, "contribution": 16.26 }
  ],
  "componentsUnavailable": ["reviewCount"],
  "candidatePoolSize": 412,
  "collectedAt": "2026-08-10T09:14:02.881Z"
}
```

The `scoreComponents` list always adds up to `score`, exactly. That is the whole point: you can re-derive the ranking from the row, change a weight, and re-rank without running anything again.

#### How the score works

1. Every product is measured on the figures AliExpress published for it.
2. Each measure is turned into a **position**: the share of the products collected in that run which this product beats on that measure, from 0 to 100.
3. The score is those positions multiplied by the weights of the chosen option, divided by the total weight.
4. A measure AliExpress does not publish for a product adds nothing for that product — nothing is filled in on its behalf. `scoreCoverage` tells you how much of the weighting a product actually earned against, and `scoreOnPublishedMeasures` shows what it would have scored if only the published measures counted.

Because positions are relative to the products collected in that run, the score ranks a shortlist. It is not an absolute rating of a product against all of AliExpress, and the row says so.

### Input reference

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `keywords` | list of text | `["phone holder"]` | Product ideas to research. Everything matching becomes a candidate. Up to 20. |
| `dealFeeds` | list of choices | `["desktop"]` | Also pull in what the site is promoting right now: `desktop`, `mobile`. |
| `country` | choice | `us` | The country you are selling into. Sets the currency, the catalogue you see, and what counts as shipping locally. |
| `preset` | choice | `proven_sellers` | `proven_sellers`, `rising_fast`, `low_competition`, `high_margin`, `local_stock`, or `custom`. |
| `customWeights` | object | — | Your own weights, used only when `preset` is `custom`. Any of the nine measures, 1 to 100 each. |
| `maxResults` | number | `100` | Size of the ranked shortlist. Max 5,000. |
| `minUnitsSold` | number | `0` | Drop products that have not sold at least this many units. Max 10,000,000. |
| `minRating` | number | `0` | Drop products rated below this, out of 5. |
| `minPrice` / `maxPrice` | number | — | Price band, in the currency of the country you chose. |
| `shipFromCountries` | list of choices | — | Keep only products dispatched from these countries. |
| `excludePromoted` | true/false | `false` | Leave promoted placements out of the shortlist. They are flagged either way. |
| `sorts` | list of choices | `["orders"]` | Which orderings to look through: `orders`, `best_match`, `price_asc`, `price_desc`. More orderings, wider pool. |
| `pagesPerKeyword` | number | `3` | Depth per idea; each step is another 20 candidates. Max 60. |
| `includeReviewCounts` | true/false | `true` | Attach the published review count to the strongest candidates. |
| `maxReviewLookups` | number | `300` | Upper bound on how many products get their review count attached. Max 2,000. |
| `parallelKeywords` | number | `2` | How many ideas to work through at once. Max 4. |

### Output fields

| Field | What it is |
| --- | --- |
| `rank`, `score` | Position in the shortlist and the weighted score behind it. |
| `scoreOnPublishedMeasures`, `scoreCoverage` | The score over only the measures this product publishes, and how much of the weighting that was. |
| `scorePreset`, `scoreWeights` | Which weighting was used and the exact weights. |
| `scoreComponents` | Per measure: the published value, whether higher or lower is better, the weight, the product's position among this run's candidates, and the points it added. |
| `componentsUnavailable` | Measures AliExpress does not publish for this product. |
| `candidatePoolSize`, `scoreBasis` | How many candidates the positions were measured against, in plain words. |
| `productId`, `globalProductId` | The product's identifiers. Some countries key a product differently; both are kept so one product is never counted twice. |
| `title`, `url`, `imageUrl` | The listing itself. |
| `unitsSold` | Exact lifetime units sold, as published. |
| `unitsSoldText` | The site's own rounded wording, e.g. "50,000+ sold", kept verbatim and never converted to a number. |
| `salesVelocityPerDay` | `unitsSold` divided by days since launch. A product listed today counts as one day old. |
| `launchDate`, `daysSinceLaunch` | The date the product was first listed, and its age. |
| `rating` | Buyer rating out of 5. |
| `reviewCount` | Number of published reviews. |
| `price`, `originalPrice`, `currency`, `discountPercent` | Current selling price, the price it is discounted from, the currency it is quoted in, and the discount. |
| `priceIsNewShopperPromo` | True when the displayed price is a first-purchase offer for new shoppers rather than the standing price. Empty where AliExpress says nothing either way. |
| `isChoice` | Whether the product carries the Choice badge. |
| `isPromoted` | Whether the product appeared as a promoted placement. Empty for products found on a deal list, which does not state it. |
| `shipFromCountry`, `shipsFromSelectedCountry` | Where it dispatches from, and whether that is your country. |
| `categoryIds` | The category ancestry the listing states, broadest first. AliExpress publishes these as identifiers and never as names, so identifiers are what you get. |
| `foundVia`, `foundIn` | Which sources turned this product up, and which idea or deal list. |
| `collectedAt` | When the row was collected. |

A run summary is also saved: candidates seen, unique products kept, repeats removed, what each filter dropped, how many products carry a velocity figure, how many carry a review count, how many were promoted placements, every currency the prices arrived in, and any source that could not be read.

### Pricing

Pay per event.

| Event | Charged when | Price |
| --- | --- | --- |
| Product scored | A product is added to your results | $0.0006 |
| Ranked shortlist entry | That product enters the ranked shortlist, deduplicated across every idea and deal list in the run, with its demand figures and full score breakdown attached | $0.0009 |

That is **$1.50 per 1,000 shortlisted products**, and you only ever pay for products that make the shortlist — everything collected, deduplicated and filtered along the way is free. The default run returns about 70 products for roughly $0.11. A serious sourcing sweep — ten ideas, two orderings, ten steps deep, shortlist capped at 500 — costs $0.75.

### Limits & what this actor cannot do

- **Nothing is estimated.** No monthly revenue figure, no profit projection, no competition index. Every number in the output was published by AliExpress; the score is a declared weighting over those numbers and shows its working.
- **The score is relative to the run.** Positions are measured against the products collected in that same run, so a score ranks a shortlist rather than rating a product in absolute terms. Widen the search and the same product can move.
- **AliExpress publishes a limited number of public results for any one search**, so a very broad idea returns what the site makes available rather than its whole catalogue. Reading more than one ordering widens the pool considerably, because each ordering shows a different slice.
- **Deal lists do not publish a launch date**, so products found only there have no sales-per-day figure and their score reflects the measures that are published for them. Products found through a search idea carry the full set.
- **Sold counts come in two forms.** Only the exact lifetime figure is used as a number. Rounded wording such as "10,000+ sold" is passed through verbatim in a separate field and never converted, because a rounded band can be three times away from the real figure.
- **The star breakdown and the review list are different populations** on this source and never reconcile, so only the published review total is reported as the review count.
- **There is no seller or store information on this source**, so no store name, seller rating or seller location is returned. It is not omitted by choice; it is not published where these products are listed.
- **Prices, stock, ratings and sales figures are a snapshot** at the moment of collection and keep changing afterwards.
- **Prices and even which products appear differ by country.** Two countries' results are not the same list in two currencies, so do not compare them product for product.
- **In some countries the displayed price is a promotional first-purchase price**, not a stable list price. Every affected product is flagged with `priceIsNewShopperPromo` so a margin ranking can be read for what it is, rather than left for you to discover.
- **Promoted placements sit inside AliExpress's own search results** — roughly a quarter of what a search returns. Every product is flagged, and you can leave them out of the shortlist entirely. Deal lists do not state it, so products found only there are left empty rather than called organic.
- **Prices are only ever compared against prices in the same currency.** If one source comes back in a different currency from the rest of a run, those products keep their own currency on the row and sit out of the price ranking and any price band, and the run summary names every currency involved.
- **Category is published as identifiers, not names.** AliExpress does not publish a readable category name anywhere on these listings, so the actor returns the identifiers rather than inventing a label for them.
- **Search terms are matched loosely by the site.** Hyphens and apostrophes are not preserved, and a term with no real matches still returns products. Where the site itself signals a loose match, the run summary says which idea it was.
- **Products that are removed or restricted in your country** are simply not published in that country's results and cannot be returned.
- Speed depends on how much you ask for and on the source site's own response times; no fixed throughput is promised.
- AliExpress's terms govern automated access. You are responsible for using the data lawfully and in line with those terms.

### FAQ

**Do I need an account on AliExpress?**
No. Nothing here is tied to an account.

**Does it need my login or password?**
No, and it has nowhere to put one.

**Can I schedule it?**
Yes. Run it weekly on the same ideas and you get a moving picture of what is climbing — the launch date and lifetime unit count make changes between runs meaningful.

**Is the data complete?**
It is complete for what AliExpress publishes publicly, and honest about the rest. Sales figures, launch dates, ratings, prices, discounts and dispatch countries come straight from the listings. Review counts are attached to as many of the strongest candidates as your limit allows. Anything the site does not publish for a product is left empty and named in `componentsUnavailable` rather than filled in.

**Why does a product with huge sales sometimes rank below one with fewer?**
Because the ranking is not sales alone. Look at `scoreComponents` on both rows: it shows exactly which measure moved which way and by how many points. If you disagree with the balance, change the weights — or pick `custom` and set your own.

**Can I get the same product twice?**
No. Products are matched across every idea and every deal list before anything is charged, including the case where the same product carries a different identifier in a different country's edition. The run summary reports candidates seen against unique products kept.

# Actor input Schema

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

One or more product searches, exactly as you would type them on the site. Every matching product becomes a candidate for the ranked shortlist. Up to 20 per run.

## `dealFeeds` (type: `array`):

Add the products currently featured on the site's own deal lists as extra candidates. They are ranked alongside your search results and never counted twice.

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

Which country's version of the site to read. This decides the currency prices come back in, which products are shown, and which products count as shipping locally to your buyers.

## `preset` (type: `string`):

Each option is simply a different weighting of the same published figures. Every figure and every weight is written onto each result, so you can always re-rank the list yourself afterwards.

## `customWeights` (type: `object`):

Only used when the option above is set to Custom. Give any of: unitsSold, salesVelocityPerDay, rating, reviewCount, price, discountPercent, daysSinceLaunch, isChoice, shipsFromSelectedCountry — each with a weight from 1 to 100.

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

The size of the ranked shortlist. Everything collected is deduplicated and ranked first, and only the best this many are returned.

## `minUnitsSold` (type: `integer`):

Only keep products the site says have sold at least this many units in total. Products the site does not publish a unit count for are left out when this is above zero.

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

Only keep products rated at or above this, out of 5. Leave at zero to keep everything, including products with no rating yet.

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

Only keep products at or above this selling price, in the currency of the country you chose. Leave empty for no floor.

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

Only keep products at or below this selling price, in the currency of the country you chose. Leave empty for no ceiling.

## `shipFromCountries` (type: `array`):

Restrict the shortlist to products dispatched from the countries you pick — the single biggest lever on delivery time for a dropshipper. Leave empty to accept any origin. Products that do not say where they ship from are reported separately rather than quietly included.

## `excludePromoted` (type: `boolean`):

Search results contain promoted placements mixed in with the rest — around a quarter of them. Every product is flagged either way; turn this on to keep them out of the shortlist entirely. Deal lists do not say whether a product is promoted, so nothing from them is removed by this.

## `sorts` (type: `array`):

The site shows a different slice of its catalogue under each ordering, so reading more than one widens the pool of candidates. Reading all four takes about four times as long.

## `pagesPerKeyword` (type: `integer`):

How deep to go into each search term's results. Each step is another 20 candidates. The site publishes a limited number of public results for any one search, so very broad terms stop before this is reached.

## `includeReviewCounts` (type: `boolean`):

Search results carry a rating but not the number of reviews behind it. Leave this on to attach the published review count to the strongest candidates, so review volume can count towards the ranking.

## `maxReviewLookups` (type: `integer`):

An upper bound on how many products get their review volume attached. The best-ranked candidates are done first.

## `parallelKeywords` (type: `integer`):

How many search terms to work through at once. Higher is faster; lower is gentler on the source site and returns slightly more distinct products.

## Actor input object example

```json
{
  "keywords": [
    "phone holder",
    "led strip lights"
  ],
  "dealFeeds": [
    "desktop"
  ],
  "country": "us",
  "preset": "proven_sellers",
  "customWeights": {
    "salesVelocityPerDay": 40,
    "rating": 25,
    "reviewCount": 20,
    "shipsFromSelectedCountry": 15
  },
  "maxResults": 100,
  "minUnitsSold": 100,
  "minRating": 4,
  "excludePromoted": false,
  "sorts": [
    "orders"
  ],
  "pagesPerKeyword": 3,
  "includeReviewCounts": true,
  "maxReviewLookups": 300,
  "parallelKeywords": 2
}
```

# Actor output Schema

## `shortlist` (type: `string`):

Every shortlisted product, best first, with each demand figure, its position in the run and the weight it carried.

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

Candidates seen, unique products kept, repeats removed, what each filter dropped, and any source that could not be read.

# 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": [
        "phone holder",
        "led strip lights"
    ],
    "dealFeeds": [
        "desktop"
    ],
    "country": "us",
    "preset": "proven_sellers",
    "customWeights": {
        "salesVelocityPerDay": 40,
        "rating": 25,
        "reviewCount": 20,
        "shipsFromSelectedCountry": 15
    },
    "maxResults": 100,
    "minUnitsSold": 100,
    "minRating": 4,
    "sorts": [
        "orders"
    ],
    "pagesPerKeyword": 3,
    "maxReviewLookups": 300,
    "parallelKeywords": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("apt_marble/aliexpress-product-research").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": [
        "phone holder",
        "led strip lights",
    ],
    "dealFeeds": ["desktop"],
    "country": "us",
    "preset": "proven_sellers",
    "customWeights": {
        "salesVelocityPerDay": 40,
        "rating": 25,
        "reviewCount": 20,
        "shipsFromSelectedCountry": 15,
    },
    "maxResults": 100,
    "minUnitsSold": 100,
    "minRating": 4,
    "sorts": ["orders"],
    "pagesPerKeyword": 3,
    "maxReviewLookups": 300,
    "parallelKeywords": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("apt_marble/aliexpress-product-research").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": [
    "phone holder",
    "led strip lights"
  ],
  "dealFeeds": [
    "desktop"
  ],
  "country": "us",
  "preset": "proven_sellers",
  "customWeights": {
    "salesVelocityPerDay": 40,
    "rating": 25,
    "reviewCount": 20,
    "shipsFromSelectedCountry": 15
  },
  "maxResults": 100,
  "minUnitsSold": 100,
  "minRating": 4,
  "sorts": [
    "orders"
  ],
  "pagesPerKeyword": 3,
  "maxReviewLookups": 300,
  "parallelKeywords": 2
}' |
apify call apt_marble/aliexpress-product-research --silent --output-dataset

```

## MCP server setup

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

```

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/Di8ero1ut8bt2eBTk/builds/iUxi4M3Wt0rKqmCiT/openapi.json
