# Shopee Scraper (`bnzz/shopee-scraper`) Actor

Shopee product and shop catalog scraper. Captures product JSON, ordered gallery images, variants, attributes, prices, sales signals, and seller metadata.

- **URL**: https://apify.com/bnzz/shopee-scraper.md
- **Developed by:** [Benz](https://apify.com/bnzz) (community)
- **Categories:** Automation, E-commerce, Social media
- **Stats:** 4 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## 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 Scraper

Extract Shopee product and shop catalog data into an Apify Dataset.

This Actor is designed for Shopee product research, catalog exports, price monitoring, and media collection workflows. It captures product metadata, ordered gallery images, description images, variants, prices, stock/sales signals, ratings, and canonical product URLs.

The public Actor writes only to the Apify stack:

```text
Shopee -> normalized product records -> Apify Dataset
run summaries/debug data -> Apify Key-value store
```

It does not write to external databases or external storage.

### What You Get

Each product record includes:

- Shopee shop ID, item ID, canonical product URL, and source title
- Product description when available
- Price in the source currency, usually THB
- Stock, sold count, historical sold count, liked count, and rating when exposed by Shopee
- Ordered gallery image URLs
- Ordered description/long image URLs
- Product option tiers and SKU/model variants
- Extraction status: `ok`, `partial`, `blocked`, or `failed`

### Best Use Cases

Use this Actor when you need:

- Product data from one or more Shopee product URLs
- A URL pool from a Shopee shop catalog
- Bulk product metadata from a seller shop
- Ordered product image URLs for content, ads, ecommerce imports, or design reference
- A clean JSON/CSV/XLSX export from Apify Dataset

### Input Modes

#### 1. Product URL Mode

Use this when you already know the products you want.

```json
{
  "productUrls": [
    "https://shopee.co.th/product/SHOP_ID/ITEM_ID"
  ],
  "maxProducts": 10
}
```

This is the safest and cheapest mode because it skips shop discovery.

#### 2. Shop Discovery Mode

Use this when you want products from a shop page.

```json
{
  "shopUrl": "https://shopee.co.th/example-shop",
  "maxProducts": 50,
  "shopScrollSteps": 20
}
```

This mode opens the shop page, scrolls, discovers product URLs, and extracts product pages.

#### 3. Full Shop Catalog Discovery

Use this when you want broader catalog coverage from a shop.

```json
{
  "shopUrl": "https://shopee.co.th/example-shop",
  "shopId": "123456789",
  "shopUsername": "example-shop",
  "fullShopCatalog": true,
  "maxProducts": 500,
  "catalogSorts": ["ctime", "sales", "pop", "relevancy"],
  "catalogMaxOffsetsPerGroup": 8
}
```

The Actor resolves the shop, calls listing/search endpoints, rotates sort modes and offsets, dedupes product IDs, and then extracts product detail pages.

#### 4. Discovery-only URL Pool

Use this before a large run to inspect how many product URLs can be found.

```json
{
  "shopUrl": "https://shopee.co.th/example-shop",
  "shopId": "123456789",
  "shopUsername": "example-shop",
  "fullShopCatalog": true,
  "catalogDiscoveryOnly": true,
  "maxProducts": 500
}
```

The dataset will contain `shopee_catalog_discovery_v1` rows instead of product-detail rows. The key-value store will include:

- `CATALOG_DISCOVERY_SUMMARY`
- `CATALOG_DISCOVERY_PRODUCTS`
- `URL_POOL_SUMMARY`

For large shops, run discovery-only first, then extract product details in batches.

### Bright Data Support

Shopee can be strict with automated traffic. The Actor supports three provider modes:

| Mode | Input value | Use when |
|---|---|---|
| Apify browser/proxy | `local_playwright` | Basic testing, smaller runs, less protected pages |
| Bright Data Browser API | `browser_api` | You need rendered browser interaction through Bright Data |
| Bright Data Unlocker API | `unlocker_api` | You want direct HTML/API extraction through Bright Data |

For Shopee catalog extraction, `unlocker_api` is usually the first mode to test because it avoids running a heavy browser for every page.

Example:

```json
{
  "shopUrl": "https://shopee.co.th/example-shop",
  "shopId": "123456789",
  "shopUsername": "example-shop",
  "brightDataProvider": "unlocker_api",
  "brightDataUnlockerApiKey": "YOUR_BRIGHT_DATA_API_KEY",
  "brightDataUnlockerZone": "YOUR_UNLOCKER_ZONE",
  "fullShopCatalog": true,
  "maxProducts": 50
}
```

Credential fields are marked as secret inputs in Apify, so saved task values are encrypted and only decrypted inside the Actor run.

### Output

Results are stored in the run default Dataset. The Output tab includes product and image views.

Example product record:

```json
{
  "output_version": "shopee_product_v1",
  "extraction_status": "ok",
  "source_platform": "shopee",
  "source_shop_id": "123456789",
  "source_shop_username": "example-shop",
  "source_item_id": "987654321",
  "source_url": "https://shopee.co.th/product/123456789/987654321",
  "source_title": "Sample dress",
  "source_currency": "THB",
  "source_price_major": 1290,
  "primary_image_url": "https://down-th.img.susercontent.com/file/example",
  "image_count": 8,
  "image_urls": [
    "https://down-th.img.susercontent.com/file/example"
  ],
  "image_manifest": [
    {
      "order": 1,
      "role": "gallery",
      "source_image_id": "example",
      "source_url": "https://down-th.img.susercontent.com/file/example"
    }
  ]
}
```

Run summaries are stored in the key-value store:

- `PRODUCT_CATALOG_SUMMARY`: product counts, status counts, and image counts
- `RUN_SUMMARY`: settings, retry counts, blocked counts, and catalog discovery summary
- `CATALOG_DISCOVERY_SUMMARY`: available when full catalog discovery is enabled
- `API_PROBE_SUMMARY`: available when API probe mode is enabled

### Recommended Large-shop Workflow

For shops with hundreds of products:

1. Run discovery-only with `maxProducts` set above the expected product count.
2. Inspect `URL_POOL_SUMMARY` and the discovery dataset.
3. Extract product details in batches of 150-200 products.
4. Retry failed/blocked product rows with `failedProductRetryPasses`.
5. Export the final Apify Dataset as JSON, CSV, XLSX, or through the Dataset API.

This is cheaper and easier to retry than crawling a large shop blindly.

### Pricing Notes For Actor Creators

If you monetize this Actor on Apify Store, prefer pay-per-event pricing over rental pricing. Apify is sunsetting the rental model in 2026, while pay-per-event supports per-result billing and AI/agentic discovery.

A simple pricing model:

- Keep the synthetic `apify-actor-start` event enabled.
- Use the automatic `apify-default-dataset-item` event for per-product pricing.
- Start with a competitive per-product price, then adjust after real cost benchmarks.

Revenue is not guaranteed. Your profit depends on paid-user usage, event price, compute usage, proxy/API costs, and Apify's creator revenue share.

See [`MONETIZATION.md`](MONETIZATION.md) for the current PPE revenue formula and example revenue scenarios.

### Troubleshooting

#### The run returns `blocked`

Try:

- Use `brightDataProvider: "unlocker_api"`
- Use a Bright Data Unlocker zone with the required target-domain permissions
- Lower `maxProducts`
- Run discovery-only first
- Increase `failedProductRetryPasses`

#### The shop does not discover all products

Try:

- Provide `shopId`
- Increase `catalogMaxOffsetsPerGroup`
- Rotate more `catalogSorts`
- Add `catalogPriceSlices`
- Run discovery-only and inspect `CATALOG_DISCOVERY_SUMMARY`

#### Product details are partial

Partial rows usually mean the page HTML had enough fallback data to identify the product, but a full structured product payload was not available. Keep `requireProductPayload: true` if you only want complete product rows.

### Local Development

```bash
npm install
npm test
npm start
```

To push to Apify:

```bash
npx apify-cli push
```

Before publishing publicly:

1. Run one product URL with export off.
2. Run a 5-product shop test.
3. Run discovery-only for a larger shop.
4. Check Dataset views and key-value summaries.
5. Configure monetization only after measuring real cost per 1,000 products.

# Actor input Schema

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

Shopee product detail URLs to extract.

## `shopUrl` (type: `string`):

Optional Shopee shop URL. The actor scrolls the shop page and enqueues discovered product URLs.

## `fullShopCatalog` (type: `boolean`):

When true, resolve the shop id, fetch seller categories, crawl category/sort/offset listing APIs, dedupe product ids, then run product detail extraction for the discovered products.

## `shopId` (type: `string`):

Optional Shopee shop id. Supplying this avoids username resolution during fullShopCatalog discovery.

## `catalogSorts` (type: `array`):

Sort strategies to rotate during fullShopCatalog discovery.

## `catalogPageLimit` (type: `integer`):

Number of listing rows to request per Shopee category/sort/offset call.

## `catalogMaxOffsetsPerGroup` (type: `integer`):

Maximum offset pages to try per seller category, sort, and price slice.

## `catalogMaxBlockedAttempts` (type: `integer`):

Stop listing discovery when this many Shopee listing calls are blocked before any products are found. Prevents wasting a full run on blocked proxy/IP paths.

## `catalogDiscoveryOnly` (type: `boolean`):

When true with Full Shop Catalog Discovery, stop after building the deduped product URL pool and do not extract product detail pages or export images.

## `catalogPriceSlices` (type: `array`):

Optional price slices for listing discovery, e.g. \[{"min":0,"max":1999},{"min":2000,"max":null}]. Leave empty for no price slicing.

## `maxProducts` (type: `integer`):

Maximum product detail pages to extract per run.

## `failedProductRetryPasses` (type: `integer`):

Number of retry passes for product-level failed or blocked extractions. The original attempt still runs first.

## `maxImagesPerProduct` (type: `integer`):

Maximum ordered Shopee image assets to keep per product after deduping resize variants and thumbnails.

## `countryCode` (type: `string`):

Apify proxy country code.

## `proxyGroups` (type: `array`):

Apify proxy groups. Residential is recommended for Shopee.

## `useProxy` (type: `boolean`):

Disable only for local debugging.

## `brightDataProvider` (type: `string`):

Use local\_playwright for the default Apify browser/proxy path, browser\_api to connect Playwright to Bright Data Browser API, or unlocker\_api to fetch Shopee HTML/JSON through Bright Data Unlocker API.

## `useBrightDataBrowser` (type: `boolean`):

Shortcut for brightDataProvider=browser\_api. Requires Bright Data Browser API auth or a full websocket endpoint.

## `brightDataBrowserAuth` (type: `string`):

Bright Data Browser API zone credentials in USER:PASS format. Prefer Apify secrets or BRIGHT\_DATA\_BROWSER\_AUTH instead of plain input.

## `brightDataBrowserWSEndpoint` (type: `string`):

Optional full Bright Data Browser API websocket endpoint. If provided, this is used instead of brightDataBrowserAuth.

## `brightDataApiKey` (type: `string`):

Bright Data Unlocker API key. Requires brightDataUnlockerZone. Browser API scraping still requires brightDataBrowserAuth or brightDataBrowserWSEndpoint.

## `useBrightDataUnlocker` (type: `boolean`):

Shortcut for brightDataProvider=unlocker\_api. Requires brightDataApiKey/brightDataUnlockerApiKey and brightDataUnlockerZone.

## `brightDataUnlockerApiKey` (type: `string`):

Bright Data Unlocker API key. You can also use brightDataApiKey or BRIGHT\_DATA\_UNLOCKER\_API\_KEY.

## `brightDataUnlockerZone` (type: `string`):

Bright Data Unlocker API zone name from the zone Overview tab.

## `brightDataUnlockerEndpoint` (type: `string`):

Optional Bright Data Unlocker direct API endpoint. Defaults to https://api.brightdata.com/request.

## `maxConcurrency` (type: `integer`):

Number of browser pages to run in parallel. Keep at 1 for Shopee stability.

## `waitMs` (type: `integer`):

Extra wait after page load so Shopee API calls and gallery images can render.

## `shopScrollSteps` (type: `integer`):

Number of scroll steps on a shop page for product URL discovery.

## `productScrollSteps` (type: `integer`):

Number of scroll steps on product pages to expose lazy-loaded gallery and description images.

## `saveDebug` (type: `boolean`):

Save response summaries, DOM image candidates, and a screenshot to key-value store for extraction QA.

## `headless` (type: `boolean`):

Run Chrome in headless mode. Default false uses headed Chrome inside Apify Xvfb, which is often less detectable.

## `warmHomePage` (type: `boolean`):

Visit Shopee home page before each target URL to establish first-party cookies and client state.

## `maxSessionAttempts` (type: `integer`):

Maximum fresh browser/proxy sessions to try for each product before emitting a blocked record.

## `sessionPoolSize` (type: `integer`):

Number of Crawlee sessions available for proxy/cookie rotation.

## `preflight` (type: `boolean`):

Run a cheap got-scraping request before browser navigation and record whether the proxy/session is already blocked.

## `skipBrowserOnPreflightBlock` (type: `boolean`):

When true, avoid browser cost if HTTP preflight already shows Shopee traffic verification. For benchmarking unblocking, keep false.

## `requireProductPayload` (type: `boolean`):

Only emit importable ok products when a structured Shopee product payload is found.

## `useFingerprints` (type: `boolean`):

Use Crawlee browser-pool fingerprints tuned to desktop Chrome/Thai locale.

## `probeApiOnly` (type: `boolean`):

Run product-detail API endpoint probes through the configured proxy without launching a browser.

## `shopUsername` (type: `string`):

Optional Shopee shop username used in normalized product output when it cannot be inferred from shopUrl.

## Actor input object example

```json
{
  "productUrls": [],
  "fullShopCatalog": false,
  "catalogSorts": [
    "pop",
    "ctime",
    "sales",
    "relevancy"
  ],
  "catalogPageLimit": 60,
  "catalogMaxOffsetsPerGroup": 3,
  "catalogMaxBlockedAttempts": 20,
  "catalogDiscoveryOnly": false,
  "maxProducts": 10,
  "failedProductRetryPasses": 1,
  "maxImagesPerProduct": 12,
  "countryCode": "TH",
  "proxyGroups": [
    "RESIDENTIAL"
  ],
  "useProxy": true,
  "brightDataProvider": "local_playwright",
  "useBrightDataBrowser": false,
  "useBrightDataUnlocker": false,
  "maxConcurrency": 1,
  "waitMs": 7000,
  "shopScrollSteps": 12,
  "productScrollSteps": 4,
  "saveDebug": false,
  "headless": false,
  "warmHomePage": true,
  "maxSessionAttempts": 5,
  "sessionPoolSize": 20,
  "preflight": true,
  "skipBrowserOnPreflightBlock": false,
  "requireProductPayload": true,
  "useFingerprints": true,
  "probeApiOnly": false,
  "shopUsername": ""
}
```

# Actor output Schema

## `products` (type: `string`):

Normalized Shopee product records with metadata, prices, image URLs, variants, and source links.

## `summary` (type: `string`):

Product counts, image counts, extraction status, and catalog-discovery summary.

## `runSummary` (type: `string`):

Execution settings, retry counts, blocked counts, and run statistics.

# 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 = {
    "productUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("bnzz/shopee-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 = { "productUrls": [] }

# Run the Actor and wait for it to finish
run = client.actor("bnzz/shopee-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 '{
  "productUrls": []
}' |
apify call bnzz/shopee-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/wmUQ5JhyJtCU0uWPA/builds/j2lfnGbUVCCh2HYOa/openapi.json
