# Lazada Scraper (`chartedsea/lazada-scraper`) Actor

Scrape Lazada search results, categories, products, reviews, sellers, and
marketplace discovery feeds without maintaining anti-bot headers, signatures,
cookies, browser sessions, or mobile API behavior.

- **URL**: https://apify.com/chartedsea/lazada-scraper.md
- **Developed by:** [Charted Sea](https://apify.com/chartedsea) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 92.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.72 / 1,000 lazada record 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

Scrape Lazada search results, categories, products, reviews, sellers, and
marketplace discovery feeds without maintaining anti-bot headers, signatures,
cookies, browser sessions, or mobile API behavior.

The Actor accepts Lazada page URLs and backend API URLs for Southeast Asian
Lazada domains. Each request is processed independently and produces one row in
the default dataset.

### Quick start

```json
{
  "requests": [
    {
      "url": "https://www.lazada.sg/catalog/?q=tshirt"
    }
  ]
}
```

A run accepts 1 to 100 requests. The Actor waits for every request to reach a
terminal state before publishing results and charging finalized events.

### Input

#### Shared options

Shared options are applied to every request. A value inside an individual
request overrides the shared value for that request.

- `requests` - Required array containing 1 to 100 Lazada requests.
- `cleanResponseBody` - Return a cleaned structured response. Default: `true`.
- `emulateMobileDevice` - Emulate Lazada mobile web traffic. Default: `false`.
- `language` - Optional Lazada language: `en`, `id`, `ms`, `th`, or `vi`.
  Apify input form default: `en`.

#### Per-request fields

- `url` - Required Lazada page or backend API URL.
- `method` - `GET` or `POST`. Default: `GET`.
- `payload` - JSON body for supported POST APIs.
- Any shared option above - Overrides that option for this request.

Unknown request options are passed to the backend for forward compatibility,
but the documented fields above are the supported public contract.

### Supported Lazada APIs

#### Product Search by Keyword or Category or Seller

- **URL Path**:
  - `https://www.lazada.${tld}/catalog/?q=${keyword}`
  - `https://www.lazada.${tld}/${categorySlug}/`
  - `https://www.lazada.${tld}/${sellerSlug}/?q=All-Products&from=wangpu&langFlag=en&pageTypeId=2`

> **Warning:**
> Avoid specifying the `page` parameter in the URL due to inefficiencies related to Lazada's pagination limitations.
> Sequential navigation from the first page is required, which can consume significant proxy traffic. For multi-page
> crawling, consider using the `productListing_crawlNextPages` parameter.

- **URL Parameters**:
  - `keyword`: Search keyword, e.g., "tshirt".
  - `categorySlug`: Category slug, e.g. "shop-computers-laptops".
  - `sellerSlug`: Seller slug, e.g. "nike".

- **Scraper Input Parameters**
  - `cleanResponseBody` (default = true): Indicates whether the response should be cleaned (true) or returned as received (false).
  - `emulateMobileDevice` (default = false): Simulates a mobile browser when set to true. This is particularly useful for this API, as it only provides consistent ordering in mobile mode.
  - `productListing_crawlNextPages` (default = false): Enables automatic crawling of subsequent pages.
  - `productListing_crawlNextPages_maxPages` (optional): Sets a cap on the number of pages to crawl.
  - `productListing_crawlNextPages_maxUniqueProducts` (optional): Limits the number of unique products to scrape. Products that appear multiple times are counted once.
  - `productListing_crawlNextPages_stopWhenNewPageOnlyContainsDuplicates` (default = true): Prevents infinite loops
    in pagination bugs by stopping when a page only contains previously listed products.
  - `productListing_crawlNextPages_stopWhenNoMorePagesIsTrue` (default = true): Stop crawling next pages if `noMorePages` equals `true` in the last response.

> **Note:**
> If `productListing_crawlNextPages` is set to `true`, all pages are scraped sequentially within a single scraping task.
> This is because Lazada requires products to be listed page by page within the same web browser session, from page 1.
> Direct access to a non-consecutive page (e.g., jumping straight to page 5) would cause Lazada to display results for the page 1.
>
> In practice, this means that a single scraping task may require more than 10min to be processed, at it may involve
> more than 100 HTTP requests (note that a random delay is added between each scrape, to reduce bot detection).
>
> The nature of this sequential crawling increases the susceptibility of the scraping task to being blocked, especially as
> successful completion depends on numerous uninterrupted requests. Although captchas can occasionally interrupt the
> session, they can be resolved; however, if no captcha is presented and the session is disrupted,
> the process need to restart from the first page.

- **Example Input**:

```json
{
  "requests": [
    // Search products with the "raspberry pi 5" keyword
    { "url": "https://www.lazada.com.my/catalog/?q=raspberry%20pi%205" },

    // Search products in the "Computers / Laptops" category
    { "url": "https://www.lazada.com.my/shop-computers-laptops/" },

    // Search products from Nike store
    { "url": "https://www.lazada.com.my/nike/?q=All-Products&from=wangpu&langFlag=en&pageTypeId=2" }
  ]
}
```

- **Example Responses**:
  - [View keyword products example response](https://www.chartedsea.com/docs/scrapers/lazada/keyword_products.json)
  - [View category products example response](https://www.chartedsea.com/docs/scrapers/lazada/category_products.json)
  - [View seller products example response](https://www.chartedsea.com/docs/scrapers/lazada/seller_products.json)

#### Product Details

- **URL Path**:
  - `https://www.lazada.${tld}/products/${productSlug}-i${productId}-s${sellerId}.html`

- **URL Parameters**:
  - `productSlug`: Product slug, e.g., "120ml-skintific-all-day-light-sunscreen-mist-spf50-pa-sunblock-spray-anti-uv-face-body-spray-120ml".
  - `productId`: Product ID (a.k.a. `itemId`), e.g. 3525761808.
  - `sellerId`: Seller ID, e.g. 22573296116.

- **Scraper Input Parameters**
  - `cleanResponseBody` (default = true): Indicates whether the response should be cleaned (true) or returned as received (false).
  - `emulateMobileDevice` (default = false): Simulates a mobile browser when set to true. Some APIs may return different results in this mode.

- **Example Input**:

```json
{
  "requests": [
    { "url": "https://www.lazada.com.my/products/120ml-skintific-all-day-light-sunscreen-mist-spf50-pa-sunblock-spray-anti-uv-face-body-spray-120ml-i3525761808-s22573296116.html" }
  ]
}
```

- **Example Response**:
  - [View example response](https://www.chartedsea.com/docs/scrapers/lazada/product_detail.json)

#### Product Reviews

- **URL Path**:
  - `https://my.lazada.${tld}/pdp/review/getReviewList?itemId=${productId}`

- **URL Parameters**:
  - `productId`: Product ID (a.k.a. `itemId`), e.g. 3525761808.

- **Scraper Input Parameters**
  - `cleanResponseBody` (default = true): Indicates whether the response should be cleaned (true) or returned as received (false).
  - `emulateMobileDevice` (default = false): Simulates a mobile browser when set to true. Some APIs may return different results in this mode.

- **Example Input**:

```json
{
  "requests": [
    { "url": "https://my.lazada.com.my/pdp/review/getReviewList?itemId=2932861112" }
  ]
}
```

- **Example Response**:
  - [View example response](https://www.chartedsea.com/docs/scrapers/lazada/product_reviews.json)

#### Product Reviews V2

- **Request Method**:
  - `POST`

- **URL Path**:
  - `https://acs-m.lazada.${tld}/h5/mtop.lazada.review.item.getpcreviewlist/1.0/`

- **Request Body**:

```json
{
  "itemId": 2770749450,
  "pageSize": 5,
  "pageNo": 1,
  "ratingFilter": 0,
  "sort": 0,
  "tagId": 0
}
```

- Parameters:
  - `itemId`: The unique identifier of the product.
  - `pageSize` (default = 5): Number of reviews.
  - `pageNo` (default = 1): Page number (starts from 1).
  - `ratingFilter` (min = 0, max = 5): 0 = all reviews, 1-5 = number of stars.
  - `sort` (default = 0): 0 = default, 1 = recent.
  - `tagId` (default = 0): 0 = all reviews, -1 = with images/videos, -3 = repeat customer. The response provides other values in the `impressionTags` field.

- **Scraper Input Parameters**
  - `emulateMobileDevice` (default = false): Simulates a mobile browser when set to true. Some APIs may return different results in this mode.

- **Example Input**:

```json
{
  "requests": [
    {
      "url": "https://acs-m.lazada.co.th/h5/mtop.lazada.review.item.getpcreviewlist/1.0/",
      "method": "POST",
      "payload": {
        "itemId": 2770749450,
        "pageSize": 5,
        "pageNo": 1,
        "ratingFilter": 0,
        "sort": 0,
        "tagId": 0
      }
    }
  ]
}
```

- **Example Response**:
  - [View example response](https://www.chartedsea.com/docs/scrapers/lazada/product_reviews_v2.json)

#### Category Tree

- **URL Path**:
  - `https://acs-m.lazada.${tld}/h5/mtop.lazada.guided.shopping.categories.categorieslpcommon/1.0/`

- **Scraper Input Parameters**
  - `emulateMobileDevice` (default = false): Simulates a mobile browser when set to true. Some APIs may return different results in this mode.

- **Example Input**:

```json
{
  "requests": [
    { "url": "https://acs-m.lazada.com.my/h5/mtop.lazada.guided.shopping.categories.categorieslpcommon/1.0/" }
  ]
}
```

- **Example Response**:
  - [View example response](https://www.chartedsea.com/docs/scrapers/lazada/category_tree.json)

#### Seller Listing

- **URL Path**:
  - `https://www.lazada.${tld}/sitemap-sellers.xml?limit=${limit}&offset=${offset}`

- **URL Parameters**:
  - `limit`: Number of sub-sitemaps to load (better equals to or less than 30).
  - `offset`: Offset for results, typically a multiple of `limit`.

- **Example Input**:

```json
{
  "requests": [
    { "url": "https://www.lazada.com.my/sitemap-sellers.xml" }
  ]
}
```

- **Example Response**:
  - [View example response](https://www.chartedsea.com/docs/scrapers/lazada/seller_listing.json)

#### Seller Details

- **URL Path**:
  - `https://www.lazada.${tld}/shop/${sellerSlug}/`

- **URL Parameters**:
  - `sellerSlug`: Seller slug, e.g., "citemalaysia".

- **Scraper Input Parameters**
  - `cleanResponseBody` (default = true): Indicates whether the response should be cleaned (true) or returned as received (false).
  - `emulateMobileDevice` (default = false): Simulates a mobile browser when set to true. Some APIs may return different results in this mode.

- **Example Input**:

```json
{
  "requests": [
    { "url": "https://www.lazada.com.my/shop/citemalaysia/" }
  ]
}
```

- **Example Response**:
  - [View example response](https://www.chartedsea.com/docs/scrapers/lazada/seller_detail.json)

#### Seller Promoted Products

- **URL Path**:
  - `https://www.lazada.${tld}/shop/site/api/shop/campaignTppProducts/query?shopId=${shopId}&sellerId=${sellerId}&itemId=${productId}`

- **URL Parameters**:
  - `shopId`: Shop ID, can be obtained from the [Seller Details](#seller-details).
  - `sellerId`: Seller ID, can be obtained from the [Seller Details](#seller-details).
  - `productId`: Any product ID from the seller.

- **Scraper Input Parameters**
  - `emulateMobileDevice` (default = false): Simulates a mobile browser when set to true. Some APIs may return different results in this mode.

- **Example Input**:

```json
{
  "requests": [
    { "url": "https://www.lazada.co.id/shop/site/api/shop/campaignTppProducts/query?shopId=3258813&sellerId=400611231032&itemId=7991896339" }
  ]
}
```

- **Example Response**:
  - [View example response](https://www.chartedsea.com/docs/scrapers/lazada/seller_campaign_tpp_products.json)

#### Keyword Listing

- **URL Path**:
  - For ID, VN: `https://www.lazada.${tld}/tag-order-last-30days-morethan0.xml?limit=${limit}&offset=${offset}`
  - For PH, TH: `https://www.lazada.${tld}/tag-order-last-60days-morethan0.xml?limit=${limit}&offset=${offset}`
  - For MY, SG: `https://www.lazada.${tld}/tag-order-last-90days-morethan0.xml?limit=${limit}&offset=${offset}`

- **URL Parameters**:
  - `limit`: Number of sub-sitemaps to load (better equals to or less than 30).
  - `offset`: Offset for results, typically a multiple of `limit`.

- **Example Input**:

```json
{
  "requests": [
    { "url": "https://www.lazada.com.my/tag-order-last-90days-morethan0.xml?limit=30&offset=0" }
  ]
}
```

- **Example Response**:
  - [View example response](https://www.chartedsea.com/docs/scrapers/lazada/keyword_listing.json)

### Raw responses

Set `cleanResponseBody` to `false` when the original Lazada response is needed:

```json
{
  "cleanResponseBody": false,
  "requests": [
    {
      "url": "https://www.lazada.sg/catalog/?q=tshirt"
    }
  ]
}
```

### Output

The default dataset contains one row per input request:

```json
{
  "marketplaceRunUuid": "...",
  "taskUuid": "...",
  "url": "https://www.lazada.sg/catalog/?q=tshirt",
  "status": "SUCCESS",
  "responseBody": {
    "productTotal": 4080,
    "products": []
  }
}
```

Output fields:

- `marketplaceRunUuid` - Marketplace run ID.
- `taskUuid` - Task ID.
- `url` - Original requested URL.
- `status` - Terminal request status.
- `responseBody` - Lazada response for a successful request.
- `error` - Error description for an unsuccessful request.

Rows remain in the same logical request order. One failed request does not hide
successful rows from the same batch.

### Pricing

Pay as you go with no subscription or monthly minimum:

- Successful Lazada request: $0.00272 per request, or $2.72 per 1,000
  successful requests.
- Proxy usage: $0.00013 per started block of 100 proxy units.
- Actor start: $0.00005 per GB of Actor memory, with a minimum of one event.
- Dataset result: $0.00001 per result written to the default dataset.

Failed or cancelled requests are not charged as successful Lazada requests.
Proxy usage varies with the requested Lazada API, response size, anti-bot
conditions, and multi-page crawling options. Use Apify's maximum total charge
setting to bound an execution's total cost.

### Charging

This is a PAY\_PER\_EVENT Actor. A completed execution can charge:

- One `csea-scrape-lazada` event per successful Lazada request.
- Finalized `csea-proxy-unit` events for proxy usage consumed by the requests.

Failed or cancelled Lazada requests are not charged as successful scrape events.
The Actor reports finalized event counts before it publishes successful output.
Use Apify's maximum total charge setting to bound an execution's cost.

### Graceful aborts and retries

A graceful Apify abort cancels known scraping tasks and waits for backend
finalization. Interrupted Actor executions persist their marketplace-run,
charging, and output state so they can resume without intentionally duplicating
charges or dataset rows.

### Operational guidance

- Monitor success rates during major Lazada campaigns.
- Expect stricter anti-bot behavior during high-traffic sales.
- Prefer bounded listing crawls over unbounded multi-page requests.
- Use mobile emulation when deterministic listing order is important.

# Actor input Schema

## `requests` (type: `array`):

One to 100 Lazada requests. URLs and scraper-specific options are validated before processing.

## `cleanResponseBody` (type: `boolean`):

Return cleaned structured Lazada responses unless a request overrides this value.

## `emulateMobileDevice` (type: `boolean`):

Emulate Lazada mobile web traffic unless a request overrides this value.

## `language` (type: `string`):

Default Lazada language header and cookie for the request batch.

## `productListing_crawlNextPages` (type: `boolean`):

Sequentially crawl additional product-listing pages unless a request overrides this value.

## `productListing_crawlNextPages_maxPages` (type: `integer`):

Default maximum product-listing pages to crawl.

## `productListing_crawlNextPages_maxUniqueProducts` (type: `integer`):

Default maximum unique products to collect from listing pages.

## `productListing_crawlNextPages_stopWhenNewPageOnlyContainsDuplicates` (type: `boolean`):

Stop when a new listing page contains only products already collected.

## `productListing_crawlNextPages_stopWhenNoMorePagesIsTrue` (type: `boolean`):

Stop when Lazada reports that no more listing pages exist.

## Actor input object example

```json
{
  "requests": [
    {
      "url": "https://www.lazada.sg/catalog/?q=tshirt"
    }
  ],
  "cleanResponseBody": true,
  "emulateMobileDevice": false,
  "language": "en",
  "productListing_crawlNextPages": false,
  "productListing_crawlNextPages_stopWhenNewPageOnlyContainsDuplicates": true,
  "productListing_crawlNextPages_stopWhenNoMorePagesIsTrue": true
}
```

# Actor output Schema

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

Complete Lazada result rows 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 = {
    "requests": [
        {
            "url": "https://www.lazada.sg/catalog/?q=tshirt"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("chartedsea/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 = { "requests": [{ "url": "https://www.lazada.sg/catalog/?q=tshirt" }] }

# Run the Actor and wait for it to finish
run = client.actor("chartedsea/lazada-scraper").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 '{
  "requests": [
    {
      "url": "https://www.lazada.sg/catalog/?q=tshirt"
    }
  ]
}' |
apify call chartedsea/lazada-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,chartedsea/lazada-scraper"
        }
    }
}

```

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/vsTGMeMItsZS3JnEt/builds/G1bpZFgVOsR4ZMQ7L/openapi.json
