# Lazada Scraper - Products, Prices, Variants & Reviews (`scrapesage/lazada-scraper`) Actor

Scrape Lazada products, prices, variants, star histograms and customer reviews across all 6 markets (SG, MY, PH, ID, TH, VN). Search by keyword, category, product URL or item ID. No login, no browser. Filter by price, rating and review count. Export CSV/JSON. Pay per result, no start fee.

- **URL**: https://apify.com/scrapesage/lazada-scraper.md
- **Developed by:** [Scrape Sage](https://apify.com/scrapesage) (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 $4.00 / 1,000 product scrapeds

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/platform/actors/running/actors-in-store#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

## Lazada Scraper - Products, Prices, Reviews & Seller Data

Scrape **Lazada** product data across **all six markets** - Singapore, Malaysia, Philippines, Indonesia, Thailand and Vietnam - by keyword, category, product URL or item ID. Every product record comes back with its price in the market's own currency, the **complete variant tree**, the **full 5-to-1 star histogram**, review counts and, optionally, the newest customer reviews nested right inside the row.

**No login. No browser. No CAPTCHA solving.** Pure HTTP against Lazada's own server-rendered product pages and its public review API, so runs are fast and cheap.

***

### What you get

#### Product record (search / product / category modes)

| Field | Notes |
|---|---|
| `title`, `itemId`, `skuId`, `url` | Canonical Lazada product identity |
| `price`, `priceText`, `currency` | In the market's own currency (SGD/MYR/PHP/IDR/THB/VND) |
| `originalPrice`, `discountText`, `discountPercent` | **Lazada does not server-render these - see the note below the table** |
| `brand`, `brandId`, `brandUrl` | Links to the brand's Lazada page |
| `categoryPath`, `categoryId`, `regionalCategoryId` | Full breadcrumb path plus Lazada's own category ids |
| `variantOptions` | Every option (Colour, Size, ...), its values, and each value's swatch image |
| `skus`, `skuCount` | Per-variant sku id and its own product URL |
| `images`, `mainImage`, `imageCount` | Every gallery image across all variants |
| `videos` | Video id + poster frame - **only a minority of listings have one; Lazada publishes no playable URL** |
| `description`, `descriptionHtml`, `highlights` | Clean text and the original HTML |
| `inStock`, `availability`, `buyLabel`, `maxOrderQuantity` | Live buyability |
| `ratingAverage`, `ratingCount`, `reviewCount` | From Lazada's own review API |
| `ratingHistogram`, `ratingPercent` | Exact 5★/4★/3★/2★/1★ counts **and** percentages |
| `reviewsWithImages`, `reviewsWithVideos`, `reviewMediaCount` | How much photo/video proof a listing has |
| `topReviews` | The newest reviews, nested (rating, text, buyer, date, variant bought) |
| `sellerId` | Numeric seller id - **Lazada does not publish the seller's name; see below** |

> **Three fields Lazada itself withholds - stated up front so nothing surprises you.**
>
> 1. **Was-price / discount %.** Lazada server-renders **only the current selling price**. Measured on 8 products pulled from Lazada's own Choice and Free-Shipping shelves (the ones most likely to be on promotion): the discount field came back empty on **8 of 8**, and each page carried exactly **one** money string. The struck-through price and the `-N%` badge are drawn client-side after the page hydrates, so there is nothing on the page to read. You still get the exact current price on **100%** of rows.
> 2. **Seller name and shop URL.** Lazada ships `seller_name` **blank to everyone** - measured empty on ordinary marketplace listings *and* on LazMall (official-store) listings, absent from the review API, and there is no shop link in the page. `/shop/{sellerId}` is not a valid Lazada URL. Rather than ship a permanently empty column or a broken link, this actor returns the **numeric `sellerId` on 100% of rows**, which is stable and groups a seller's whole catalogue.
> 3. **Product video URL.** Gallery video entries carry a `videoID` and a poster frame but no playable link, so that is exactly what you get - no fabricated URLs.
>
> Everything else measured **100% populated** on a real 8-product run: title, price, currency, brand, category path, images, variant tree, sku list, description, stock, and the whole rating block.

#### Review record (reviews mode)

`rating` · `content` · `ratedAspects` (the per-aspect scores buyers fill in, e.g. *Sound Quality: 10/10*) · `buyerName` · `buyerAvatar` · `boughtDate` · `reviewDate` · `variantBought` · `skuId` · `verifiedPurchase` · `likeCount` · `upVotes` / `downVotes` · `images` · `videoUrl` + `videoCover` · `sellerReply` · `productTitle` · `productUrl` · `isCrossBorder`

Reviews are paged 20 at a time straight from Lazada's public review API. Photos (measured 10/21), videos (3/21), seller replies (5/21) and avatars (3/21) exist only where that buyer or seller actually provided them - the counts match Lazada's own summary block exactly, so nothing is being missed.

***

### Modes

| Mode | What it does |
|---|---|
| **search** | Find products by keyword across Lazada's catalogue |
| **product** | Scrape specific product URLs or bare item IDs |
| **category** | Browse a category by name |
| **reviews** | Pull customer reviews for the given products |

**One mode returns exactly one record type**, so a CSV export never columnises on the union of four different shapes and leave you with mostly-blank cells.

#### How search works (and what it is honestly not)

Lazada walls its on-site search JSON, so this actor searches **Lazada's own published product sitemaps** instead - up to ~616,000 live products per market, each carrying its full title in the URL. Keyword matching runs over those titles and results are ranked by match quality.

That means: **results are ranked by keyword match against Lazada's catalogue, not by Lazada's internal search-relevance ranking.** For price monitoring, catalogue building, competitor tracking, assortment analysis and review mining - the things people actually buy this data for - that is what you want. If you need Lazada's exact on-site result *order* for a query, this is not that.

You can choose which catalogue to search with the `catalogue` option: `all` (default, freshest - measured 9/10 URLs still live), `lazmall` (official stores, 10/10 live), `choice`, `freeShipping`, `trending`, or `selling` (Lazada's "ordered in the last 30 days" list - demand-ranked, but Lazada regenerates it on a lag so roughly **40% of its entries are already delisted**).

***

### Example input

```json
{
  "mode": "search",
  "market": "SG",
  "searchTerms": ["wireless earbuds"],
  "catalogue": "all",
  "maxItems": 50,
  "includeReviews": true,
  "maxReviewsPerProduct": 5,
  "minReviews": 10,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

Filter as you go with `minPrice`, `maxPrice`, `minRating` and `minReviews` - these run **inside** the crawl, so `maxItems` returns that many *matching* products rather than being eaten by rows that get thrown away.

### Example output (trimmed)

```json
{
  "type": "product",
  "market": "SG",
  "itemId": "3427720191",
  "title": "Vention IPX4 Bluetooth 5.4 Wireless Earbuds ... Noise Cancelling Earphone",
  "price": 32.99,
  "currency": "SGD",
  "brand": "Vention",
  "categoryPath": ["Audio", "Headphones & Headsets"],
  "inStock": true,
  "skuCount": 3,
  "variantOptions": [
    { "name": "Color Family", "values": [
      { "name": "White", "image": "https://laz-img-sg.alicdn.com/p/c03f...jpg" },
      { "name": "Black", "image": "https://laz-img-sg.alicdn.com/p/34c9...jpg" }
    ]}
  ],
  "ratingAverage": 4.8,
  "reviewCount": 213,
  "ratingHistogram": { "star5": 190, "star4": 15, "star3": 5, "star2": 1, "star1": 2 },
  "sellerId": "1000061401"
}
```

***

### Reliability

Lazada rate-limits **by IP**: the same product page that is throttled on one exit returns the full document on another. This actor is built around that measured fact - each parallel worker owns its own residential proxy session (its own IP), sessions are retired after a few requests, and **every retry rotates to a fresh IP** rather than re-hitting the throttled one. Measured 4/8 success on a single cold attempt, which the rotation takes to ~98% per product.

A throttle is **never** treated as "this product has no data", and it never crashes the run: blocked runs finish **Succeeded** with a status message telling you to re-run. The actor also reads its own run deadline and stops cleanly before the platform can kill it, so a big job ends with partial results instead of a TIMED-OUT run.

### Use with AI assistants (MCP)

This actor works as a tool for AI assistants through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) - point Claude, ChatGPT or your own agent at it and ask for Lazada product, price or review data in plain language.

### Agent-ready: autonomous payments (x402 & Skyfire)

This actor is **agent-ready** — AI agents can discover it, run it, and **pay for it autonomously**, with no Apify account and no human in the loop. It uses [pay-per-event](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event) pricing and [limited permissions](https://docs.apify.com/platform/actors/development/permissions), so it qualifies for Apify's agentic-payment standards:

- **[x402](https://docs.apify.com/platform/integrations/x402)** — an open, HTTP-native payment protocol. Agents pay per run in USDC on the Base network directly through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) — no account, no API key.
- **[Skyfire](https://docs.apify.com/platform/integrations/skyfire)** — agent-to-service payments for fully autonomous AI-agent workflows.

Building an AI agent, MCP tool, or autonomous data pipeline? This scraper is ready to plug in and pay as it goes.

***

### Pricing

Pay per result, **no start fee**:

- **Product scraped - $0.004** - the complete record above, product page + review API in one pass.
- **Review scraped - $0.001** - one full customer review.

### Legal & fair use

This actor collects **publicly visible product information** - the same pages Lazada serves to any visitor and publishes in its own sitemaps for search engines. It does not log in, does not touch cart, checkout or account pages (which Lazada's `robots.txt` is the only thing to disallow, and which this actor never requests), and collects no personal data beyond the public display name a reviewer chose to show on their own public review. You are responsible for using the data in line with Lazada's terms and applicable law, including data-protection rules where reviewer names are involved.

# Actor input Schema

## `mode` (type: `string`):

search = find products by keyword. product = scrape specific product URLs or item IDs. category = browse a product category by name. reviews = customer reviews for the given products. Each mode returns exactly ONE record type, so your CSV never has half-empty columns.

## `market` (type: `string`):

Which Lazada country site to scrape. Prices come back in that market's own currency.

## `searchTerms` (type: `array`):

One or more keywords, e.g. "wireless earbuds". Used by the search mode. Leave empty and the actor runs a small sample search so it always returns real data.

## `productUrls` (type: `array`):

Lazada product page URLs (https://www.lazada.sg/products/...-i1234567890.html) or bare numeric item IDs. Used by the product and reviews modes.

## `categoryKeywords` (type: `array`):

Category words to browse, e.g. "laptop", "running shoes". Used by the category mode.

## `catalogue` (type: `string`):

all = Lazada's main product sitemap (default; ~616,000 live products, measured 9/10 still listed). lazmall / choice / freeShipping / trending = Lazada's own curated shelves. selling = products that took orders in the last 30 days - demand-ranked, but Lazada regenerates that sitemap on a lag so roughly 40% of its entries are already delisted and return fewer results per run.

## `maxItems` (type: `integer`):

How many records to return. 0 means as many as the run's time budget allows.

## `includeReviews` (type: `boolean`):

Nests the newest reviews inside every product record (rating, text, buyer, date, variant bought). The rating average, review count and 5-to-1 star histogram are always included regardless.

## `maxReviewsPerProduct` (type: `integer`):

How many reviews to nest inside each product record when the option above is on.

## `minPrice` (type: `integer`):

Only keep products at or above this price, in the market's own currency.

## `maxPrice` (type: `integer`):

Only keep products at or below this price, in the market's own currency.

## `minRating` (type: `integer`):

Only keep products whose average customer rating is at least this (1-5).

## `minReviews` (type: `integer`):

Only keep products with at least this many customer reviews - a good proxy for proven sales.

## `concurrency` (type: `integer`):

How many products to fetch at once. Each parallel worker uses its own proxy session (its own IP), which is what keeps Lazada from rate-limiting the run. Raise it for speed, lower it if you see throttling.

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

Residential proxy is strongly recommended - Lazada throttles datacenter IPs. The exit country is pinned to the chosen market automatically.

## Actor input object example

```json
{
  "mode": "search",
  "market": "SG",
  "searchTerms": [
    "wireless earbuds"
  ],
  "catalogue": "all",
  "maxItems": 50,
  "includeReviews": true,
  "maxReviewsPerProduct": 10,
  "concurrency": 6,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

All scraped Lazada records as JSON items in the default dataset.

# 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 = {
    "mode": "search",
    "market": "SG",
    "searchTerms": [
        "wireless earbuds"
    ],
    "catalogue": "all",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapesage/lazada-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 = {
    "mode": "search",
    "market": "SG",
    "searchTerms": ["wireless earbuds"],
    "catalogue": "all",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapesage/lazada-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "market": "SG",
  "searchTerms": [
    "wireless earbuds"
  ],
  "catalogue": "all",
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scrapesage/lazada-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=scrapesage/lazada-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/645CMgn3lIRlJoMyA/builds/XPA0chb7kwuK0adot/openapi.json
