agenttoolworks

Guide, measured 2026-10-26 and 2026-10-27

How to scrape AliExpress, and why most IPs never see a product

AliExpress shows its listings to anyone, signed in or not. Its search pages carry their results in the HTML, and its product pages fetch their details from one JSON call. Both can be read logged out with plain HTTP. The hard part is Alibaba's gate: most new IPs are refused at their first product. Here are the requests, the gate, what changes with the ship-to country, and where listings stop, with our measurements.

Search and category pages carry their data

A keyword search and a category page are the same kind of page, and both are rendered on the server. The results are not in the visible markup you would parse with selectors: they are in a JSON object the page's script reads.

a search page and a category page
GET https://www.aliexpress.com/w/wholesale-wireless-earbuds.html?page=2
GET https://www.aliexpress.com/category/63705/earphones-headphones.html?page=2
    -> about 850 KB of HTML (about 150 KB on the wire), with the page's data:
       window._dida_config_._init_data_ = { data: { ... } }
         60 cards a page, and the total number of results

Each card gives the product ID, title, image, sale price and currency, original price, discount, units sold as AliExpress writes it (10,000+ sold), rating, ship-from country and whether it is sponsored. Search cards carry no store name: that comes with the product details. Region and currency follow the exit IP unless you set them, which is what the site's own country and currency menus do with the aep_usuc_f cookie. A category or search URL pasted from a browser keeps its own sort and filters.

Search pages answered on every pool we tried (no proxy, datacenter and residential); category pages on datacenter IPs answered 6 of 8. In a cloud run of our Actor, 1,200 search rows came back in 58 seconds with 0 refusals on 26 pages (2026-10-27). Search pages have the same per-IP ceiling as product details, though: two datacenter IPs of a probe run were refused on their 11th page, and new IPs were not.

One trap cost us a build. The cards sit one data level deeper than a trimmed sample page suggests, and our first cloud build, written against trimmed test pages, read no search page at all. It was fixed before anything was published. Test a parser on a page saved whole, as the site served it.

Listings stop long before the announced total

A search page holds 60 cards, and AliExpress announces a total it does not list. For "phone case" it announced 183,827 results, served 60 pages, and answered page 61 without a product list: 2,978 distinct products, a product repeated on a later page counted once (run 3I6g9bQPiarhfZQBT, 2026-10-27, under 5 minutes without details). That is one search. To go further, split it: one search per category, or narrower keywords, each with its own pages.

15% to 21% of the cards in our runs (ivpzfa25Jju4YT7ng and 3I6g9bQPiarhfZQBT) were not ordinary listings but AliExpress's new-user offer, "{FREE} with any purchase", with no price block. A parser that reads only the price block gets no price for them. Their welcome price and list price are in the card's own data, the same welcome price the product page's data gives a logged-out visitor. We take the price from there, keep the offer in its own field, and check that data's unit against the page's priced cards: unless at least 9 in 10 of them agree, the price stays null rather than guessed.

The product page is an empty shell

Fetch /item/<id>.html and you get about 78 KB of HTML with no product in it: the page is client-rendered (window._d_c_.isCSR = true, and window.runParams is empty). Its script then asks Alibaba's API gateway on acs.aliexpress.com for the details, with the standard Alibaba H5 signature. That call is the one to make:

the product details, as the page fetches them
GET https://www.aliexpress.com/item/<id>.html
    -> about 78 KB: a client-rendered shell, no product data in it

GET https://acs.aliexpress.com/h5/mtop.aliexpress.address.shipto.division.get/1.0/
    -> a light call the page also makes; its answer sets the _m_h5_tk cookie,
       whose first part is the token

GET https://acs.aliexpress.com/h5/mtop.aliexpress.pdp.pc.query/1.0/
      sign = md5(token & t & appKey & data)
      data = product ID, language, currency, country (the ship-to), clientType "pc"
    -> about 75 KB of JSON: PRICE and SKU (every variant, its price and stock),
       SHIPPING (the options to that country), SHOP_CARD_PC, PC_RATING,
       HEADER_IMAGE_PC, PRODUCT_PROP_PC, DESC, GLOBAL_DATA

The gateway answers a call without a token with an empty-token error and sets the cookie the token comes from. The product page also makes a light call, a 153-byte answer, that sets the same cookie, so a reader can take its token there and spend its detail calls on products. In the two runs of our 1,000-product access test on 2026-10-27, the light call returned the token 484 times out of 484.

The answer holds every variant (SKU) with its option names, price and stock, the price range, the shipping options for the country asked, the store and its positive feedback rate, rating, reviews count, units sold, images, category and specifications. On the 995 products of our access test (2026-10-26), title, price, currency, variants, stock, shipping, store, images and reviews count were filled 100%, orders 92.2% and rating 73.7%: products without reviews have no rating.

Two traps in the answer. Some sellers type a placeholder stock meaning "plenty" (99,999, 200,000, 999,996 per SKU): flag it rather than add it up. And a free shipping option carried the currency CNY in the answers we read; use the requested currency for a free option.

Alibaba's gate is decided per IP

The details call is guarded by Alibaba's risk control, and it decides per IP, at the first call. A refused IP gets the punish answer: FAIL_SYS_USER_VALIDATE in JSON, or a redirect to a slider captcha page. We never saw a login redirect, an HTTP 403 or an HTTP 429 in its place. What we measured with our probe on 2026-10-26:

What we askedWhat came back
Search pages, datacenter IPs26 of 26 answered
Category pages, datacenter IPs6 of 8 answered
Product details call, residential IPs of any country50 of 283 new IPs let through (17.7%)
Product details call, datacenter IPs10 of 60 new IPs let through
Product details call, US residential IPs only0 of 15 let through (a small sample)
The same call with Chrome's TLS fingerprint2 of 16 US residential IPs, 0 of 11 of any country
Datacenter IPs used up by a run 8 minutes earlier25 of 27 sessions refused at once
Headless Chromium, residential8 of 8 products on one US IP, 0 of 2 on another pool; more than 40 times the cost per product

Three things follow. An IP let through is served about 10 products and then refused: nine sessions of one probe run were refused exactly after their 10th product, paced 1.2 to 2.2 seconds apart. A refused IP stays refused: for at least 7 minutes on datacenter, and about an hour for our own laptop's IP. And neither warm-ups (loading the product page first, or the page's analytics device ID) nor Chrome's TLS fingerprint changed the gate in our small samples; the IP decides.

So the reader that works asks each new IP once, drops it at the first refusal, and retires it after 10 products, before the refusal measured on the 11th. In our Actor's 1,000-product run on 4 parallel IPs, 439 of 555 new IPs were refused at their first call and 116 let through, about one in five, and 98 of those served 10 products (run hK0tyCOaGAXR5YzyQ, 2026-10-27): 998 of 1,000 products delivered in 20 minutes. On 8 parallel IPs, 1,000 of 1,000 in 544 seconds, with 24% of detail calls refused against 31% on 4 (run 7QQ1p5Y1reU9NDx8x).

What it does not do: answer the slider. The IP that gets it is dropped and never used again, every refusal is counted in the run's summary, and if 60 new IPs in a row are refused, the run stops and says so. It does not move to a headless browser either: in our measurement that cost more than 40 times as much per product as the plain requests.

Prices, availability and shipping change with the country

The ship-to country is a parameter of the details call, independent of the exit IP: a German IP got US and UK answers. The same product, read for six countries in one session (run cNwNenzgH5H0ndVW8, 2026-10-26, USD, every option shipped from China):

Ship toPrice rangeDelivery optionFeeDays
United States22.61 to 26.37AliExpress Selection Standard$1.995 to 10
United Kingdom20.33 to 23.74AliExpress Selection Premium shipping$1.994 to 7
Germany33.49 to 37.33AliExpress Selection Standard$1.997 to 10
France35.34 to 39.47AliExpress Selection Standard$1.997 to 10
Brazil21.38 to 24.60AliExpress Selection Standard$3.5011 to 18
Australia24.07 to 27.30AliExpress Selection Standard$1.995 to 10

Some answers are not prices at all. Products stocked in a US warehouse answered "unavailable in your location" (SITEM_BAN_NO_AVAIL_SKU) for the five other countries: 15 of the 24 answers of that run. That answer is real, not a disguised block: the same session got a UK answer and an unavailable one for the US on the same product. Some sellers are barred in EU countries (SSELLER_BAN_DSA, in France and Germany for a product sold to the US and the UK, run hKJqds2ocDKjr5kBT). Across our runs of 50 products to the US, the UK, Germany, France and Brazil, 17% to 28% of answers were unavailable ones, none for the US.

So a market comparison needs one details call per product and country, and a row per pair that says which it was: priced, or not sold there. Currency is asked for in the same call: in USD, EUR (France) and GBP (UK), every row and every shipping fee came back in the currency asked (runs mmfimdMHePHeYJJ9W and Ps7BZp0rkpbak5kZR, 2026-10-27).

Monitoring prices and stock

A price tracker compares each product with the last time it was read, for the same ship-to country and currency, SKU by SKU: a price up or down, a SKU sold out or back in stock. Two rules keep it useful. Stock counts going down with sales are not a change, only in stock against sold out. And when a seller relists a product under new SKU IDs, compare the product's lowest price and whether any SKU is in stock too, or a relisting under new SKU IDs reads as no change.

Our Actor does this with onlyChanges and a monitorName: it keeps the comparison in a key-value store of your own Apify account, reads every product to compare it, and returns and charges only the new and changed ones. The first run returns everything it reads.

Or call our Actor through the Apify API

Our AliExpress scraper does all of the above in one run: keywords, categories and product URLs, several ship-to countries with one row each, the per-IP rotation without ever answering the slider, change mode, and a partial status instead of a silent short result. With the official apify-client for Node.js:

node.js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('agenttoolworks/aliexpress-scraper').call({
    keywords: ['wireless earbuds'],
    maxItems: 50,
    shipTo: ['US', 'DE'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((r) => r.status === 'ok').map((r) => [r.shipTo, r.title, r.price, r.shippingFee]));

It costs $1.50 per 1,000 detailed product rows, one per product and ship-to country ($1.35 on Apify's Silver plan, $1.20 on Gold and up), and $0.50 per 1,000 search rows without details, proxies included. Rows for products not sold to a country, not found, failed or duplicated are free, and Apify's free plan covers about 3,300 detailed products a month.

What we left out

Questions

Can you scrape AliExpress without a browser?

Yes. Search and category pages carry their results as JSON inside the HTML, 60 cards a page. The product page is an empty shell, but the JSON call its script makes for the details answers a plain HTTP client that signs it the same way. In our measurement a headless browser cost more than 40 times as much per product as those plain requests.

Why does AliExpress show a slider captcha to my scraper?

Alibaba's risk control decides per IP, at the first product request, and refuses most new IPs with its slider page: in our 1,000-product run, 439 of 555 new IPs were refused at their first call and 116 let through, about one in five (run hK0tyCOaGAXR5YzyQ). An IP let through is then served about 10 products before it is refused too, and a refused IP stays refused. Our Actor drops that IP for a new one and never answers the slider.

How many products can an AliExpress search return?

About 3,000 in our measurement: the "phone case" search listed 60 pages and answered page 61 without a product list, 2,978 distinct products out of the 183,827 results AliExpress announced (run 3I6g9bQPiarhfZQBT, 2026-10-27). To go further, split the search into categories or narrower keywords.

Why does AliExpress show a different price in each country?

The ship-to country is a parameter of the product details call, and the answer changes with it: price, availability and delivery options. One product was priced 22.61 to 26.37 USD for the US and 35.34 to 39.47 USD for France, read in the same session, before a $1.99 shipping fee to each.

Why do some AliExpress search cards have no price?

15% to 21% of the cards in our search runs were AliExpress's new-user offer ("{FREE} with any purchase"), which shows no price block. The welcome price and the list price are in the card's own data.

Public product listings only: no login, no account, no buyer's personal data. Not affiliated with AliExpress or Alibaba Group.