# Shopee Product Catalog & Variant Scraper (`incognito_mode/shopee-product-catalog-scraper`) Actor

Scrape Shopee product pages across 11 countries: title, full description with inline images, all photos and videos, specifications, category breadcrumb, seller vouchers, and every variant with its Colour/Size options resolved - plus the seller's profile. No login or API key.

- **URL**: https://apify.com/incognito\_mode/shopee-product-catalog-scraper.md
- **Developed by:** [Elena Vance](https://apify.com/incognito_mode) (community)
- **Categories:** E-commerce, Developer tools, AI
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 products

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

## Shopee Product Catalog & Variant Scraper

Pull complete **product content** off Shopee — across **11 marketplaces**, with
no API key, no login, no browser and no residential proxy.

Built for catalogue work: PIM population, content migration, competitor
assortment tracking, brand and listing monitoring, and building product
datasets for search or LLM use.

***

### Read this first: what is and isn't here

**This Actor does not return price, stock, ratings or units sold.** That is a
property of Shopee, not of the Actor, and being straight about it up front is
more useful than burying it.

Shopee serves the product page with those fields deliberately stripped — its
own payload literally lists them as removed:

```json
"removed_fields": ["product_price.price", "product_price.price_before_discount",
                   "product_price.discount", "item.bundle_deal_info"]
```

…and it returns a **constant placeholder of `10`** for every variant's stock,
verified across 24 SKUs on three marketplaces. This Actor omits that field
rather than passing a fake number through as inventory.

Reaching the real numbers means defeating Shopee's anti-fraud device
attestation — which does not work even from a genuine headful Chrome (see
[`docs/architecture.md`](docs/architecture.md)). Actors that do sell those
fields pay a commercial unblocking service per request, and that cost lands in
their pricing.

**Everything below is real, complete and stable.**

***

### What you get

| Group | Fields |
| --- | --- |
| **Identity** | item ID, shop ID, canonical URL, marketplace, currency |
| **Content** | title, brand, condition, plain-text description, and the description as **ordered blocks** so inline images keep their position |
| **Media** | every product photo, videos with a playable MP4 URL + duration + thumbnail, size-chart image |
| **Taxonomy** | Shopee's internal category path *and* the consumer-facing breadcrumb, both as `{id, name}` |
| **Specifications** | seller-declared attributes as `{name, value}` — material, origin, warranty… |
| **Variants** | the option axes (Colour → options + swatch images) **and** every SKU with its options resolved to readable names |
| **Promotions** | seller vouchers with minimum spend, discount amount or percentage, % used, and validity window |
| **Logistics** | free shipping, pre-order, estimated shipping days, wholesale, ships-from location, cross-border |
| **Seller** | rating, review total, followers, listing count, response rate, cancellation rate, badges |

#### The variant join is the point

Shopee stores variants as two disconnected halves: the option names live in one
place, and each SKU refers to them only by positional index (`[2, 1]`). Raw
exports leave you to reassemble that. This Actor does the join:

```json
"variations": [
  { "name": "Color", "options": ["White", "Blue Camouflage", "Rosy Camouflage"],
    "optionImages": ["https://down-sg.img.susercontent.com/file/4acb03…"] },
  { "name": "Size", "options": ["14: Insole 11.5cm", "15: Insole 12.0cm", "…"] }
],
"variants": [
  { "modelId": 92932478374, "name": "White,20: Insole 14.5cm",
    "options": { "Color": "White", "Size": "20: Insole 14.5cm" },
    "isPreOrder": false, "estimatedShippingDays": 1, "isAvailable": true }
]
```

### Example output (trimmed)

```json
{
  "itemId": 6192497619,
  "shopId": 178158839,
  "region": "sg",
  "url": "https://shopee.sg/product/178158839/6192497619",
  "title": "Kids Baby Lightweight Sandals Summer Boys Mesh Sandals 0-3Yrs Girls Infant Prewalker",
  "condition": "new",
  "isAvailable": true,
  "categories": [
    { "id": 100633, "name": "Baby & Kids Fashion" },
    { "id": 100692, "name": "Boy Shoes" },
    { "id": 101060, "name": "Sandals" }
  ],
  "attributes": [
    { "name": "Country of Origin", "value": "China" },
    { "name": "Material", "value": "Rubber" }
  ],
  "variantCount": 24,
  "vouchers": [
    { "code": "BABY70201", "minSpend": 11.0, "discountAmount": 0.33,
      "percentUsed": 32, "endsAt": "2026-10-03T15:59:00Z" }
  ],
  "videos": [
    { "url": "https://mms.vod.susercontent.com/…/…default.mp4",
      "definition": "V540P", "durationSeconds": 12 }
  ],
  "shopLocation": "Mainland China",
  "isCrossBorder": true,
  "createdAt": "2021-06-22T07:01:57Z",
  "shop": {
    "shopId": 178158839, "name": "Yienws.sg", "itemCount": 684,
    "followerCount": 16446, "ratingStar": 4.86, "ratingTotal": 36688,
    "responseRate": 85, "cancellationRate": 0
  }
}
```

### Input

A Shopee product needs **two** IDs — a shop ID and an item ID. All of these
carry both:

```json
{
  "products": [
    "https://shopee.sg/product/178158839/6192497619",
    "https://shopee.sg/Kids-Baby-Sandals-i.178158839.6192497619",
    "178158839/6192497619",
    "https://shopee.co.id/product/165796339/7454342119"
  ],
  "includeShop": true,
  "includeDescription": true
}
```

Paste a single item ID and the Actor tells you exactly what's missing rather
than failing vaguely.

| Option | Default | Notes |
| --- | --- | --- |
| `products` | — | Required. Product URLs or `shopId/itemId` pairs. |
| `region` | `sg` | Applies only to bare pairs; URLs use their own domain. |
| `includeShop` | `true` | Seller profile, fetched **once per shop** and reused. |
| `includeDescription` | `true` | Largest part of a record; off for a slimmer dataset. |
| `maxItems` | `100` | Hard cap on stored rows. |
| `proxyConfiguration` | off | Leave off — see below. |

### Marketplaces

Singapore · Malaysia · Indonesia · Thailand · Vietnam · Philippines · Taiwan ·
Brazil · Mexico · Colombia · Chile

Verified live on all of them. Shopee has exited Spain, France, India and
Poland, so those are not offered.

### Speed and cost

One product is **one HTTP request**. The seller profile is one more per *shop*,
not per product, so 500 products from one seller cost 501 requests, not 1,000.
No browser is launched. Measured: 4 products across 3 countries in ~4 seconds.

No proxy is used unless Shopee actually blocks an IP, and then the Actor
escalates on its own — datacenter first (included in every Apify plan, free
tier included), residential only if your plan has it.

### Use it for

- **Catalogue and PIM population** — titles, specs, images, variants and
  category paths in one structured row per product.
- **Assortment tracking** — watch which SKUs and options a competitor adds or
  drops over time by scheduling a run.
- **Content migration** — move listings between marketplaces with the
  description blocks and images intact.
- **Search / LLM datasets** — clean, deduplicated product records with a real
  category path.
- **Voucher monitoring** — seller promo codes with their spend thresholds and
  expiry.

### Related

Pair with the **Shopee Shop & Seller Profile Scraper** for seller-level
metrics, and the category and brand-directory Actors to discover what to feed
in.

# Actor input Schema

## `products` (type: `array`):

One entry per product. A Shopee product needs BOTH a shop ID and an item ID, so all of these work:

• https://shopee.sg/product/178158839/6192497619
• https://shopee.sg/Kids-Baby-Sandals-i.178158839.6192497619 (the product's own URL)
• 178158839/6192497619 (a bare shopId/itemId pair)

A URL pointing at another country's Shopee is scraped from that country, so a mixed-country list works in one run.

## `region` (type: `string`):

Which Shopee country to use for entries that are NOT full URLs. Full URLs always use their own domain.

## `includeShop` (type: `boolean`):

Adds the seller behind each product: rating, review count, followers, listing count, response rate, cancellation rate and badges. The profile is fetched once per shop and reused, so scraping 500 products from one seller costs one extra request in total.

## `includeDescription` (type: `boolean`):

Adds the seller's plain-text description plus an ordered block list that keeps inline images in their original position. This is the largest part of a record, so switch it off for a slimmer dataset.

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

Hard cap on how many products are stored. The run stops as soon as it is reached.

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

Leave off. Every request calls Shopee directly first, which costs nothing. If an IP is blocked the Actor escalates on its own: first to a datacenter proxy (included in every Apify plan, free tier included), then to residential only if your plan has it. No residential add-on is required.

## Actor input object example

```json
{
  "products": [
    "https://shopee.sg/product/178158839/6192497619"
  ],
  "region": "sg",
  "includeShop": true,
  "includeDescription": true,
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing every scraped product.

# 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 = {
    "products": [
        "https://shopee.sg/product/178158839/6192497619"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("incognito_mode/shopee-product-catalog-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 = {
    "products": ["https://shopee.sg/product/178158839/6192497619"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("incognito_mode/shopee-product-catalog-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 '{
  "products": [
    "https://shopee.sg/product/178158839/6192497619"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call incognito_mode/shopee-product-catalog-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,incognito_mode/shopee-product-catalog-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/pScSLBqAf8dUAsk0a/builds/MEtlbQ9VkM06LhWcB/openapi.json
