# Lazada Singapore Product Scraper (`alwaysprimedev/lazada-sg-product-scraper`) Actor

Scrape Lazada Singapore product details from URLs or the public sitemap. Fast, pay-per-result, no setup.

- **URL**: https://apify.com/alwaysprimedev/lazada-sg-product-scraper.md
- **Developed by:** [Always Prime](https://apify.com/alwaysprimedev) (community)
- **Categories:** Automation, E-commerce, SEO tools
- **Stats:** 3 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 results

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

## 🛒 Lazada Singapore Product Scraper

⚡️ **Scrape any Lazada SG product page into clean structured JSON.** Pay only for the products you actually get. No setup, no proxies to configure, no captcha tickets to buy. 🚀

![Python 3.11](https://img.shields.io/badge/python-3.11-blue)
![Output JSON CSV XLSX](https://img.shields.io/badge/output-JSON%20%7C%20CSV%20%7C%20Excel-brightgreen)
![Built for Apify](https://img.shields.io/badge/built%20for-Apify-orange)

***

### 🤖 Why this scraper

- 💰 **Pay-per-result, $9 per 1 000 products** — among the cheapest Lazada actors on the store, by design.
- 🧠 **Sitemap-aware** — point it at "Recent 30 days" and it walks Lazada's own product sitemap so you never have to maintain a URL list.
- 📦 **Full product record** — title, price, currency, brand, full breadcrumb category, all photos, every SKU variant + its option axes (color, size, etc.), seller ID, stock state, and the full HTML description.
- 🔁 **Incremental mode** — pass a `since` date and the scraper only fetches products whose sitemap `lastmod` is newer. Daily refreshers stay tiny.
- 🪶 **Lightweight** — 256 MB Apify memory, no headless browser, no Selenium. Fast and cheap to run.
- ⏱️ **Real-time progress** — periodic STATS write to the key-value store so you can monitor mid-run.

***

### 🚀 Quick start

1. Click **Try for free** at the top of this page.
2. Either paste a few Lazada product URLs in the *Product URLs* field, or pick a *Sitemap mode* (start with **Recent 30 days**).
3. Set *Max items* (start with 25 for a quick test) and hit **Start**.
4. When the run finishes (~5–15 s per product), open the **Storage → Dataset** tab and click **Download** in JSON, CSV, or Excel.

***

### 📥 Input

| Field | Description | Default |
| --- | --- | --- |
| **Product URLs** | List of Lazada SG `/products/...iXXXX.html` URLs. Use this when you already have a target list (your own catalog, a competitor's SKUs, etc.). | one example URL |
| **Sitemap mode** | If you don't have URLs, the scraper pulls them straight from Lazada's public sitemap. *Recent 30 days* covers the freshest catalog (products with sales in the last 30 days). *All* walks the full sitemap (millions of URLs). | `none` |
| **Max items** | Stop after this many successfully scraped products. `0` = unlimited. | `50` |
| **Scrape full product details** | Off = return only `{url, id, scraped_at}` (a cheap inventory-diff mode). On = full product record per URL. | `on` |
| **Only products updated since** | Optional ISO date. In sitemap mode, skip products whose sitemap `lastmod` is older. Perfect for daily refresh runs. | empty |
| **Categories** | Optional list. Paste any Lazada SG category URL (e.g. `https://www.lazada.sg/shop-mobile-phones/`) or just type a name (e.g. `Mobiles`, `Wireless Earbuds`). The scraper walks the product sitemap and **skips URLs whose slug doesn't contain any of the category keywords — before fetching them**, so proxy bandwidth stays minimal. A second pass verifies the product's breadcrumb actually matches, eliminating false positives. Multiple categories = OR. | empty |
| **Concurrency** | Parallel page fetches. 5 is a healthy default; pushing past 10 stops helping. | `5` |

> **How the category filter works**: Lazada's category landing pages (`/shop-mobile-phones/`) render listings via client-side JavaScript, so a pure-HTTP scraper can't read them. This actor takes a different route: it pulls candidate URLs from Lazada's own product sitemap, then keeps only the URLs whose slug contains a keyword derived from your category name. The result is a category-scoped scrape with the same low proxy cost as an unfiltered run — at the cost of recall (a product whose slug doesn't carry a category keyword will be missed). Combine with Sitemap mode = "Recent 30 days" for a fresh slice.

***

### 📤 Output (sample, one record)

```json
{
  "url": "https://www.lazada.sg/products/magnolia-wafer-ice-cream-sandwich-raspberry-ripple-durian-yam-chocolate-blueberry-ripple-i2470744437.html",
  "id": "2470744437",
  "sku_id": "14715727747",
  "title": "Magnolia Wafer Ice Cream Sandwich - Raspberry Ripple, Durian, Yam, Chocolate, Blueberry Ripple",
  "brand": "Magnolia",
  "brand_id": "16832",
  "categories": ["Groceries", "Frozen", "Ice Cream"],
  "price": 1.68,
  "price_display": "$1.68",
  "currency": "SGD",
  "discount_pct": null,
  "in_stock": true,
  "seller_id": "1158102029",
  "seller_name": null,
  "rating": null,
  "review_count": null,
  "image_main": "https://laz-img-sg.alicdn.com/p/9ba2a4e4105e4c3ba9184da5b951bd91.jpg",
  "images": [
    "https://laz-img-sg.alicdn.com/p/9ba2a4e4105e4c3ba9184da5b951bd91.jpg",
    "https://laz-img-sg.alicdn.com/p/2c8d6d77b5128f4a35551a3fad55fe55.jpg"
  ],
  "options": [
    { "name": "flavour", "values": ["Raspberry Ripple", "Durian", "Yam", "Chocolate", "Blueberry Ripple"] }
  ],
  "variants": [
    { "sku_id": "14715727747", "inner_sku_id": "2470744437_SGAMZ-14715727747", "prop_path": "flavour:Raspberry Ripple", "url": "https://www.lazada.sg/products/...-s14715727747.html" }
  ],
  "description_html": "<article>…</article>",
  "country": "SG",
  "language": "en_SG",
  "scraped_at": "2026-05-14T23:42:11Z"
}
```

> **Note on `rating`, `review_count`, `seller_name`**: these load asynchronously on the live Lazada page and aren't in the server-rendered product page. They'll be `null` on every record in the v0.1 release. A v1.0 enrichment pass is planned.

***

### 💡 Use cases

| Who | What for |
| --- | --- |
| 🛒 Online sellers | Track competitor prices, stock, and new SKUs daily. |
| 📊 Market researchers | Build the Singapore e-commerce dataset they always wanted — by category, by brand, by price band. |
| 🤖 ML / AI teams | Train product classifiers, recommendation models, or image embeddings on a real catalog. |
| 🔍 Brand monitors | Find counterfeit listings of your products on Lazada. Daily incremental mode keeps the alert list fresh. |
| 💸 Arbitrage shoppers | Spot Lazada SG ↔ Shopee / Amazon SG price gaps in real time. |

***

### ✅ Tips & tricks

- **Daily refresh**: Schedule a daily Apify run with `sitemapMode: recent_30days` and `since: <yesterday>`. Only new/changed products will be fetched — minimal cost.
- **Big batches**: For 10k+ products, raise concurrency to 10. Above that, Lazada starts slowing responses without giving you more throughput.
- **CSV-flat output**: When downloading as CSV, the nested `options` and `variants` arrays auto-flatten with column prefixes — great for Excel pivots.

### ❓ FAQ

**Q: Why isn't `rating`/`review_count` filled in?**  Lazada's product page loads those values via a second JavaScript call after the page renders, so they're not in the page HTML. We're working on an opt-in v1.0 enrichment pass.

**Q: Can I scrape from search queries like "iphone case"?**  Not in v0.1 — the search page also loads results via JavaScript. For now, use sitemap mode or paste category/product URLs directly. Free-text search is on the roadmap.

**Q: Does it support other Lazada countries (TH, MY, PH, VN, ID)?**  v0.1 is SG-only. The same data shape exists on every Lazada region, so multi-country support is planned for v1.

**Q: Will my IP get blocked?**  No — the scraper handles all anti-bot bypass internally. You don't need to bring or configure proxies.

**Q: How fast is it?**  ~5–10 seconds per product at default concurrency. A 1 000-product run usually finishes in 5–10 minutes.

***

### 🛟 Support

Open an issue on this actor's *Issues* tab and we'll take a look. PRs welcome from anyone running their own fork.

# Actor input Schema

## `startUrls` (type: `array`):

Paste any number of Lazada SG product URLs (the long /products/...iXXXX.html links). The scraper visits each one and returns the full product record. Leave empty to use the sitemap mode below.

## `sitemapMode` (type: `string`):

If you don't have a URL list, the scraper can pull URLs straight from Lazada's public sitemap. "Recent 30 days" is the recommended starting point — it's the freshest sub-sitemap Lazada publishes and contains products with sales in the last 30 days.

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

Stop the run after this many successfully scraped products. 0 = unlimited (use carefully with sitemap modes).

## `scrapeDetails` (type: `boolean`):

Turn off to return only URLs + product IDs (a cheap discovery / inventory-diff mode). Leave on to fetch the full product page for every URL and return title, price, images, variants, seller, etc.

## `categoryUrls` (type: `array`):

Optional. Paste category URLs from Lazada's home page (e.g. https://www.lazada.sg/shop-mobile-phones/) or just type category names (e.g. "Mobiles", "Wireless Earbuds"). The scraper walks Lazada's product sitemap and keeps only products whose URL slug AND/OR breadcrumb match — without ever fetching the irrelevant ones, so proxy bandwidth stays low. Multiple categories work as OR. Combine with Sitemap mode = "Recent 30 days" to harvest a fresh vertical.

## `since` (type: `string`):

Optional. When set, sitemap-mode runs skip products whose sitemap <lastmod> is older than this date — useful for incremental refresh runs. Ignored when scraping from the URL list above. Leave blank for a full pull.

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

Number of product pages to fetch in parallel. 5 is a good balance of speed and politeness; pushing past 10 may trigger temporary rate-limits and hurt throughput.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.lazada.sg/products/magnolia-wafer-ice-cream-sandwich-raspberry-ripple-durian-yam-chocolate-blueberry-ripple-i2470744437.html"
  ],
  "sitemapMode": "none",
  "maxItems": 50,
  "scrapeDetails": true,
  "categoryUrls": [],
  "concurrency": 5
}
```

# Actor output Schema

## `listings` (type: `string`):

No description

## `listingsCsv` (type: `string`):

No description

## `listingsXlsx` (type: `string`):

No description

## `consoleView` (type: `string`):

No description

# 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 = {
    "startUrls": [
        "https://www.lazada.sg/products/magnolia-wafer-ice-cream-sandwich-raspberry-ripple-durian-yam-chocolate-blueberry-ripple-i2470744437.html"
    ],
    "maxItems": 50,
    "categoryUrls": [],
    "since": "",
    "concurrency": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("alwaysprimedev/lazada-sg-product-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 = {
    "startUrls": ["https://www.lazada.sg/products/magnolia-wafer-ice-cream-sandwich-raspberry-ripple-durian-yam-chocolate-blueberry-ripple-i2470744437.html"],
    "maxItems": 50,
    "categoryUrls": [],
    "since": "",
    "concurrency": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("alwaysprimedev/lazada-sg-product-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 '{
  "startUrls": [
    "https://www.lazada.sg/products/magnolia-wafer-ice-cream-sandwich-raspberry-ripple-durian-yam-chocolate-blueberry-ripple-i2470744437.html"
  ],
  "maxItems": 50,
  "categoryUrls": [],
  "since": "",
  "concurrency": 5
}' |
apify call alwaysprimedev/lazada-sg-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alwaysprimedev/lazada-sg-product-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/eiYEvg8coQqq89SKH/builds/HMp86OrYfQIRngQMQ/openapi.json
