# Shopee Product Details Scraper (`titan_network/shopee-product-details-scraper`) Actor

Collect Shopee product details from product URLs or shop/item IDs. Batch up to 100 unique products with JSON output and free per-product failure diagnostics.

- **URL**: https://apify.com/titan_network/shopee-product-details-scraper.md
- **Developed by:** [Titan Network](https://apify.com/titan_network) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 product detail collecteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Shopee Product Details Scraper do?

Collect Shopee product details from product URLs or shop/item ID pairs and save the results to an Apify Dataset. Use the JSON results in product research, catalog analysis, or your own application through the Apify API.

You do not need to supply a Shopee login, proxy, or separate service API key. Each run accepts up to 100 unique products, removes duplicates, and reports individual failures alongside successful results.

Availability and response time depend on the collection service; a successful result is not guaranteed for every product. See the input settings for supported URLs and region.

### Quick start

1. Paste a current product URL into **Product URLs (Taiwan)**. Copy the full product page URL rather than a shortened share link.
2. Start with one product and set **Maximum concurrency** to `1` for your first test.
3. Run the Actor and wait for collection to finish. Individual requests can take several minutes. Collection has a 30-minute window; some products may be skipped if protection limits are reached.
4. Open **Product detail results** in the Output tab. Check `status` and expand `data` for the product payload. Use **Collection diagnostics** for a compact status table.
5. Export the Dataset as JSON to preserve nested product data. **Run summary** shows successful, failed, skipped, and duplicate counts.

The input form includes one example product verified during release checks. Replace it with the product you want to collect. Availability can change. The examples below use illustrative IDs:

```json
{
  "startUrls": [
    { "url": "https://shopee.tw/product/12345678/9876543210" }
  ],
  "maxConcurrency": 1
}
```

### Accepted product URLs

The URL and ID input options currently use the Taiwan region (`TW`). For URLs, use `shopee.tw` or `www.shopee.tw` with HTTP or HTTPS. Both product URL formats are accepted:

```text
https://shopee.tw/product/{shopId}/{itemId}
https://shopee.tw/{product-slug}-i.{shopId}.{itemId}
```

Other markets, unsupported schemes, URLs with credentials, and nonstandard ports are rejected as free invalid-input diagnostics. Embedded URL credentials are removed from diagnostic input values. Query parameters are not needed to identify the product. The submitted URL is preserved as `sourceUrl`. Short links, redirect resolution, search pages, shop listings, keyword discovery, and review pagination are outside this Actor's scope.

The market value is `TW` for accepted URLs. ID-only submissions carry no inferred market information.

### Input settings

| Field | Required | Description |
|---|---|---|
| `startUrls` | Either this or `items` | Array of objects containing a full product `url`. Up to 100 entries, in both the form and API. |
| `items` | Either this or `startUrls` | Array of `{ "shopId": "...", "itemId": "..." }` pairs. Both IDs must be decimal strings copied from a supported product URL. Up to 100 entries. |
| `maxConcurrency` | No | Integer from `1` to `2`; defaults to `2`. Start with `1` when checking availability. |

You can combine URLs and ID pairs. Across both fields, a run can contain at most **100 unique `shopId:itemId` pairs**. Matching pairs are duplicates even if submitted with the two accepted host forms or different parameters. The first occurrence supplies the output's URL and market when present. Results may arrive in a different order from the input.

IDs are normalized as decimal strings without leading zeroes, so `01:002` and `1:2` refer to one product and trigger at most one result charge within the run. Large string IDs retain their full precision.

For ID-only input:

```json
{
  "items": [
    { "shopId": "12345678", "itemId": "9876543210" }
  ],
  "maxConcurrency": 1
}
```

ID-only results omit `market` and `sourceUrl`. Completely empty input fails before collection begins, with a status message asking for `startUrls` or `items`. Incorrect input containers fail validation; malformed array entries become diagnostic rows while valid products continue. Non-empty input containing only invalid targets produces diagnostic rows and a failed run.

### Product data and exports

Each unique processed product produces one Dataset row with a stable envelope. Successful rows have `status: "completed"`; the collected payload is stored under `data` without renaming its product fields.

Before charging, the Actor checks for a matching shop and item ID, a non-empty product title, and no reported inner collection error. Empty payloads, task acknowledgements, mismatched products, and inner error responses become free `invalid_response` diagnostics. Optional price, stock, and other attributes can be absent.

This is an **anonymized excerpt from a verified cloud response**. IDs, URL and title are replaced, and only selected fields are shown. It is not a guarantee that every response has these fields:

```json
{
  "platform": "shopee",
  "inputKey": "12345678:9876543210",
  "market": "TW",
  "shopId": "12345678",
  "itemId": "9876543210",
  "sourceUrl": "https://shopee.tw/product/12345678/9876543210",
  "status": "completed",
  "collectedAt": "2026-10-15T09:01:46.329Z",
  "data": {
    "data": {
      "item": {
        "shop_id": 12345678,
        "item_id": 9876543210,
        "title": "Anonymized cotton shorts",
        "currency": "TWD",
        "price": 150400000,
        "price_min": 150400000,
        "price_max": 150400000,
        "stock": null,
        "item_rating": {
          "rating_star": 4.9772727272727275
        }
      }
    },
    "error": null,
    "error_msg": null
  }
}
```

Verified responses included product identity, title, price, image, and rating/review structures. Their nesting, availability, currency, and units depend on the response. Inspect `data` before building downstream mappings; do not assume every product contains the same attributes or apply a fixed price conversion.

The excerpt above reflects observed output structure. Product prices, availability, and ratings change over time; the raw numeric price is preserved without conversion.

| Output field | Meaning |
|---|---|
| `platform` | Always `shopee`. |
| `inputKey` | Product identity, usually `shopId:itemId`; invalid inputs use their input position. |
| `shopId`, `itemId` | Identifiers preserved as strings. Absent for inputs that cannot be parsed. |
| `market`, `sourceUrl` | `TW` and the original accepted URL, when available. Omitted for ID-only input. |
| `status` | `completed`, `failed`, or `skipped`. Always check this field. |
| `collectedAt` | Time the result row was prepared, in UTC. |
| `data` | Unmodified product payload on successful rows. |
| `errorCode`, `errorType`, `errorMessage`, `retryable` | Diagnostics on failed or skipped rows. |

**Product detail results** includes `data`. **Collection diagnostics** omits the product payload and helps identify failed products. JSON exports preserve nested data; CSV and Excel are most useful after selecting the nested fields you need. Duplicate inputs do not produce additional rows.

#### Run summary

The default Key-Value Store's `OUTPUT` record contains:

| Field | Meaning |
|---|---|
| `submittedCount` | Total occurrences, including invalid inputs and duplicates. |
| `uniqueCount` | Valid unique product pairs scheduled or represented in the run. |
| `duplicateCount` | Valid repeated product pairs removed. |
| `successfulCount`, `failedCount`, `skippedCount` | Counts by result status; failed count includes invalid inputs. |
| `chargedCount` | Custom successful-result billing events; `0` in non-monetized preview runs. |
| `datasetId` | Dataset containing this run's rows. |
| `stoppedBy` | Present when stopped for `auth_error`, `circuit_open` (legacy recovery), `resource_limit`, or `budget_limit`. |

One successful product can make a mixed batch finish successfully. Inspect counts and rows rather than relying only on run status. Zero successful products normally means a failed run; reaching a paid event budget is a graceful stop and can finish with zero successes.

### Errors and troubleshooting

| Diagnostic | What to do |
|---|---|
| `invalid_input` | Use a full product URL or numeric strings for both IDs. |
| `not_found` | Check that the product still exists and is accessible. |
| `risk_control` | Collection was blocked. Try later; repeated runs may encounter the same restriction. |
| `rate_limited` | Reduce concurrency and wait before a later attempt. No automatic retry is performed. |
| `timeout` | Collection did not finish in time. No automatic retry is performed. A task may still be executing; avoid immediately resubmitting it. |
| `upstream_error` | The service rejected or could not complete the request. It is not automatically repeated because its submission outcome may be uncertain. |
| `invalid_response` | No valid product payload was returned. Retry later or report the Run ID. |
| `auth_error` | Service configuration issue. Contact the developer with the Run ID; a user-supplied key is not required. |
| `circuit_open` | Several service failures stopped remaining work. Retry affected products later. |
| `budget_limit` | A paid event budget prevented delivery. Increase the budget before resubmitting skipped products. |
| `resource_limit` | Requests stopped for a failure, request-count, time, or recovery limit. Read the first protection diagnostic. Wait and investigate repeated failures before starting another run. Contact the developer with the Run ID if collection remains unavailable. |

A diagnostic row includes the original input and a sanitized error message. Malformed URL entries or non-scalar IDs use placeholders rather than copying an arbitrary object. For example:

```json
{
  "platform": "shopee",
  "inputKey": "12345678:9876543210",
  "market": "TW",
  "shopId": "12345678",
  "itemId": "9876543210",
  "sourceUrl": "https://shopee.tw/product/12345678/9876543210",
  "originalInput": "https://shopee.tw/product/12345678/9876543210",
  "status": "failed",
  "collectedAt": "2026-10-15T00:00:00.000Z",
  "errorCode": "404",
  "errorType": "not_found",
  "errorMessage": "The product was not found.",
  "retryable": false
}
```

`retryable` describes whether a failure may be transient; it does not enable automatic retries. This release never automatically repeats a collection request. A new run may succeed after conditions change.

#### Collection protection

- At most **100 unique products and 100 collection requests per run**, with **2 requests in flight** at most. These limits cannot be increased through input fields.
- Stop starting new requests after **3 consecutive collection failures** or **10 total collection failures**. All collection errors count, including timeouts and invalid product responses. Locally rejected input does not consume this failure allowance.
- The collection window is **30 minutes**, retained on restart. Each request can take at most **310 seconds**. A new request starts only when that full timeout still fits in the window, so scheduling can stop around minute 24:50. The default platform timeout is 31 minutes to allow result cleanup; a shorter user timeout may interrupt earlier.
- Already submitted requests are allowed to settle. With concurrency 2, at most one other request can remain in flight when the failure threshold is reached. This can increase observed failures to 4 consecutive or 11 total; no new request is admitted after the threshold is observed.
- A durable per-run submission journal is written before each request. Restarting this run does not automatically submit the same product again. Uncertain prior submissions, malformed protection state, or a journal write failure stop further submissions. Partial older runs without a journal also stop adding new work.
- Protection-skipped rows are **not billed**. Successful valid results already collected may still be delivered and billed. This Actor cannot cancel tasks already submitted to the collection service.

These are per-run protections. They do not implement a shared quota or failure cooldown across newly created runs. Avoid repeatedly creating runs for the same failures.

### Pricing

Pay-per-event prices are in USD and depend on your Apify subscription tier. Check the Pricing tab for the current rates.

| Apify tier | Per 1,000 successful product details | Per successful product detail |
|---|---:|---:|
| FREE | $6.99 | $0.00699 |
| BRONZE | $5.99 | $0.00599 |
| SILVER | $5.49 | $0.00549 |
| GOLD | $4.99 | $0.00499 |
| PLATINUM / DIAMOND | $4.99 | $0.00499 |

The only billing event is `product-detail-collected`, once per successfully delivered unique product detail. Failed, duplicate, timed-out, skipped, and undelivered products do not trigger it. There is no startup fee or additional Dataset-row fee; diagnostic rows do not trigger a paid event.

Standard Actor-run platform usage is included in the result price. Separate services you use outside the run, such as subsequent storage or exports, follow your Apify plan. Check the Pricing tab and set a run spending limit before submitting a batch. The FREE row refers to Apify's Free subscription tier; it is not a promise of free product results or a custom trial quota.

### Use the Shopee scraper API

Install the official JavaScript client with `npm install apify-client`, set `APIFY_TOKEN` in your environment, and run:

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('titan_network/shopee-product-details-scraper').call({
  startUrls: [
    { url: 'https://shopee.tw/product/12345678/9876543210' },
  ],
  maxConcurrency: 1,
});

// listItems returns a page. Iterate when handling larger datasets.
const page = await client.dataset(run.defaultDatasetId).listItems();
for (const row of page.items) {
  if (row.status === 'completed') console.log(row.data);
  else console.warn(row.inputKey, row.errorType, row.errorMessage);
}

const summary = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('OUTPUT');
console.log(summary?.value);
```

Replace the illustrative URL with your product and use an account with access to the Actor. Prefer starting a run and fetching its Dataset over a single HTTP request waiting for an entire batch. Failed runs may still contain useful diagnostics in their Dataset.

### FAQ and support

#### Do I need a Shopee account or a proxy?

No. Enter URLs or ID pairs; collection configuration is managed by the Actor developer.

#### Can I collect a shop, search results, or all reviews?

This release retrieves individual product details. It does not discover links or paginate reviews, even if a returned payload contains some review information.

#### Will repeating an input return cached data for free?

A new run creates new collection requests and can incur new result charges. Duplicate removal and Dataset-based recovery apply within the same run. They are not a cross-run cache or an exactly-once guarantee across services.

If recovery detects an invalid stored completed result, an older non-canonical ID format, or an oversized legacy Dataset, the Actor stops and asks you to contact the developer with the Run ID. It does not automatically collect and charge those products again.

#### How do I report a problem?

Use the Actor's Issues tab once published. Include the Run ID, market, and `errorCode`/`errorType`. Do not post API tokens or private credentials. Keep sensitive inputs out of public issues.

### Responsible use

Collect and use only data you are authorized to access. Respect applicable laws, privacy and intellectual-property rights, marketplace terms, and rate limits. You are responsible for how you use and retain results.

Not affiliated with or endorsed by Shopee.

### 中文说明

提交商品详情链接，或字符串格式的 `shopId` / `itemId`，每次最多处理 100 个去重商品。无需提供 Shopee 登录信息、代理或额外服务密钥。首次建议用一个商品、并发 `1` 测试。

请按输入选项所示地区填写商品链接或 ID。支持的链接格式见上方 Input settings；不符合格式的输入会输出免费错误诊断。

每 1,000 条成功交付的详情：FREE $6.99、BRONZE $5.99、SILVER $5.49、GOLD / PLATINUM / DIAMOND $4.99，币种均为美元。FREE 指 Apify 订阅档位，不代表免费采集额度。

输出入口 **Product detail results** 提供含 `data` 的完整结果，**Collection diagnostics** 用于查错，**Run summary** 提供计数。成功为 `completed`，失败为 `failed`，跳过为 `skipped`；批次成功不代表每个商品成功。建议导出 JSON 保留嵌套字段，商品价格单位和字段结构以实际返回为准。

采集可能需要几分钟，遇到超时可稍后单独重跑。仅对成功交付触发 `product-detail-collected` 事件，失败诊断、重复和未交付结果不触发该事件；不收启动费和额外 Dataset 行费。标准 Actor 运行资源包含在结果价中，运行之外的存储、导出等服务以 Apify 方案为准。

收费前会核对商品 ID、非空标题和内层错误状态；空结果、任务受理回执及商品不匹配不会作为成功详情收费。价格、库存等可选字段可以缺失。恢复旧运行时若发现无效成功记录，会停止并提示联系开发者，避免自动重复采集计费。

# Changelog

This Actor's version history is a separate document: https://apify.com/titan_network/shopee-product-details-scraper/changelog.md

# Actor input Schema

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

Paste full product URLs using /product/{shopId}/{itemId} or -i.{shopId}.{itemId}. Short share links and shop/search pages are not supported. Only http/https URLs on shopee.tw or www.shopee.tw are accepted; other markets, credentials, and nonstandard ports are rejected as free invalid-input diagnostics. Provide URLs, ID pairs, or both; duplicates share one result.

## `items` (type: `array`):

Optional alternative to URLs for Taiwan products only. Copy shopId and itemId from a shopee.tw product URL and enter them as strings containing decimal digits only. ID-only results omit market and sourceUrl. Across URLs and ID pairs, submit at most 100 unique shopId:itemId pairs.

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

Number of products collected at the same time (1-2, default 2). Start with 1 for an availability test. Requests are not automatically retried. Collection stops starting new requests after 3 consecutive failures, 10 total failures, or when insufficient time remains in the 30-minute collection window.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://shopee.tw/product/131441298/25020742445"
    }
  ],
  "maxConcurrency": 2
}
```

# Actor output Schema

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

Full Dataset rows including the nested data payload on completed products. Failed and skipped products contain diagnostics instead.

## `diagnostics` (type: `string`):

Compact view of identifiers, source URLs, statuses, and error details. Omits the product payload.

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

Submitted, unique, duplicate, successful, failed, skipped, and charged counts, plus the Dataset ID and stop reason when present.

# 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": [
        {
            "url": "https://shopee.tw/product/131441298/25020742445"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("titan_network/shopee-product-details-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": [{ "url": "https://shopee.tw/product/131441298/25020742445" }] }

# Run the Actor and wait for it to finish
run = client.actor("titan_network/shopee-product-details-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": [
    {
      "url": "https://shopee.tw/product/131441298/25020742445"
    }
  ]
}' |
apify call titan_network/shopee-product-details-scraper --silent --output-dataset

```

## MCP server setup

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