DEV Community

Gio Rich
Gio Rich

Posted on

Getting full Alibaba product pages as JSON: price tiers, SKUs, specs and the supplier behind them

I built this actor; it's a paid tool on Apify with a free trial credit.

Alibaba search results tell you a price range and an MOQ. The decisions get made on the product page: what the unit price is at 500 pieces versus 5,000, how long production takes at your quantity, which variants exist, whether the CE or FCC certificate is real (with a number), and whether the supplier is a 140-person factory with a 2,400 m² floor or a three-person trading office. Copying that out of 20 tabs by hand is the slow part of sourcing.

I'm an 18-year-old engineering student, and I built Alibaba Product Details Scraper to turn product URLs, product IDs or a keyword into one clean JSON row per product, over plain HTTP. This post covers how it works, calling it from Python and Node, what a row looks like, and a small project: a side-by-side supplier comparison for a shortlist.

How it works

An Alibaba product page carries its data as one big JSON object that the page renders from. The actor fetches the page, cuts that object out with a string-aware brace walk, and maps it to flat fields: the quantity price ladder, MOQ, SKU matrix, specifications, certificates, lead time bands, sample price, customization options, package size and weight, and the supplier card (business type, years, staff, factory size, store rating, on-time dispatch rate, response time, online revenue band, orders in the last six months, ranking badge). No contact person names, phones or emails are collected.

Give it keywords instead of URLs and it first calls the JSON endpoint Alibaba's own search page uses, then opens each product it finds. Removed products are reported in a run summary and never charged. It connects directly and only retries blocked requests through a proxy.

Calling it from Python

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("rel8ble/alibaba-product-details-scraper").call(run_input={
    "productUrls": [
        "https://www.alibaba.com/product-detail/ALOVA-Latest-Model-Bluetooth-6-0_1601511059774.html",
        "1601617846699",
    ],
    "searchTerms": ["yoga mat"],
    "maxProductsPerSearch": 30,
})

for p in client.dataset(run["defaultDatasetId"]).iterate_items():
    tiers = ", ".join(f"{t['minQuantity']}+: ${t['price']}" for t in p["priceTiers"])
    print(p["title"][:50], "| MOQ", p["moq"], "|", tiers or p["priceText"], "|", p["supplierName"])
Enter fullscreen mode Exit fullscreen mode

The same from Node:

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('rel8ble/alibaba-product-details-scraper').call({
    searchTerms: ['bluetooth speaker'],
    maxProductsPerSearch: 20,
    includeAds: false,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const p of items) console.log(p.priceMin, p.moq, p.leadTimes[0]?.days, p.supplierYearsOnAlibaba, p.certificates.map((c) => c.name).join('/'), p.url);
Enter fullscreen mode Exit fullscreen mode

What a row looks like

From a real run, trimmed:

{
    "productId": "1601511059774",
    "title": "ALOVA Latest Model Bluetooth 6.0 Earphone IPX7 Bone Conduction Headset Waterproof Headphone Wireless Earbuds with Mic",
    "priceTiers": [
        { "minQuantity": 10, "maxQuantity": 89, "price": 9.9 },
        { "minQuantity": 90, "maxQuantity": 1999, "price": 8.5 },
        { "minQuantity": 2000, "maxQuantity": 4999, "price": 7.4 },
        { "minQuantity": 5000, "maxQuantity": null, "price": 6.5 }
    ],
    "moq": 10,
    "samplePrice": 22,
    "skuCount": 4,
    "leadTimes": [{ "minQuantity": 2, "maxQuantity": 90, "days": 31 }, { "minQuantity": 91, "maxQuantity": 1000, "days": 35 }],
    "certificates": [{ "name": "FCC", "type": "PRODUCT", "number": "2AP4POPENEAR-X1", "validity": "07/25/2022 - 12/30/9999" }],
    "packageSize": "15.5X9X18",
    "packageWeightKg": 0.5,
    "supplierName": "Shenzhen Alex Technology Co., Ltd.",
    "supplierBusinessType": ["Manufacturer", "Trading Company"],
    "supplierYearsOnAlibaba": 11,
    "supplierStaffCount": 142,
    "supplierFactorySizeSqm": 2400,
    "supplierRating": 4.5,
    "onTimeDeliveryRate": "100.0%",
    "onlineRevenue": "US$1,500,000+",
    "ordersLast6Months": 242,
    "supplierRanking": "#2 leading manufacturer in Earphone & Headphone & Accessories"
}
Enter fullscreen mode Exit fullscreen mode

Project: a supplier comparison for your order size

Goal: for a shortlist of products, print the unit price at the quantity you actually plan to order, the lead time for that quantity, the landed weight, and the supplier signals that matter, sorted by price.

from apify_client import ApifyClient

QTY = 1000
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("rel8ble/alibaba-product-details-scraper").call(run_input={
    "searchTerms": ["insulated water bottle"],
    "maxProductsPerSearch": 40,
    "includeAds": False,
})

def price_at(p, qty):
    for t in p["priceTiers"]:
        if t["minQuantity"] <= qty and (t["maxQuantity"] is None or qty <= t["maxQuantity"]):
            return t["price"]
    return p["priceMin"]

def lead_at(p, qty):
    for l in p["leadTimes"]:
        if l["minQuantity"] <= qty <= (l["maxQuantity"] or 10**9):
            return l["days"]
    return None

rows = []
for p in client.dataset(run["defaultDatasetId"]).iterate_items():
    if p["moq"] and p["moq"] > QTY:
        continue
    rows.append((price_at(p, QTY), lead_at(p, QTY), p))

for price, lead, p in sorted(rows, key=lambda r: r[0] or 1e9)[:15]:
    certs = "/".join(c["name"] for c in p["certificates"][:3]) or "-"
    print(f"${price:>6} @ {QTY} | {lead or '?':>3} days | {p['packageWeightKg'] or '?'} kg | "
          f"{p['supplierYearsOnAlibaba']} yrs | {'verified' if p['verifiedSupplier'] else 'unverified':10} | "
          f"{p['onTimeDeliveryRate'] or '-':>6} on time | {certs} | {p['supplierName']}")
Enter fullscreen mode Exit fullscreen mode

The cheap way to cover a whole category is two steps: scan thousands of search cards with our Alibaba search scraper (filter by price, MOQ and country there), then send only the shortlist's url column to this actor for the full pages.

Pricing and limits

$2.50 per 1,000 products, no start fee. Removed products, invalid URLs, duplicates and failed requests are never charged. The long HTML description is not included (Alibaba loads it in a separate frame). Supplier capability fields appear only when the supplier shows them: staff count and factory size on about a quarter of products in my tests, online revenue on about half. Prices are USD list prices as shown to a US visitor.

Store page: https://apify.com/rel8ble/alibaba-product-details-scraper

This article was drafted with AI and published by me.

Top comments (0)