# Shopee Product Scraper (`nice_dev/shopee-product-scraper`) Actor

Scrape Shopee products in 8 markets (SG, ID, MY, PH, TH, VN, TW, BR) by keyword or URL: price, discount, rating, seller location, labels. Optional full product details and seller profile. Export to JSON, CSV or Excel.

- **URL**: https://apify.com/nice_dev/shopee-product-scraper.md
- **Developed by:** [Nice Dev](https://apify.com/nice_dev) (community)
- **Categories:** E-commerce, MCP servers
- **Stats:** 3 total users, 2 monthly users, 98.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 is Shopee Product Scraper?

**Shopee Product Scraper** extracts **products from [Shopee](https://shopee.sg)** in **8 markets** (Singapore, Malaysia, Philippines, Thailand, Vietnam, Indonesia, Taiwan and Brazil): **name, price and photo** of every product of a keyword search, a category or a shop, plus the **discount, rating, seller location and promotion labels** that keyword searches and shop pages show, and the **units sold** when Shopee shows them. Paste a product link to read that product's page. Optional extras: every **variant** (colour, size), description, specifications, brand, shop vouchers, and the **seller's shop rating and followers**. It works as a **Shopee API alternative**: run it on a schedule to track prices, call it from your code, or plug it into Make, Zapier or n8n.

Pick a **market**, type a **keyword** (`iphone 15`) or paste any Shopee link, click **Start**, and download the products in JSON, CSV or Excel. No login, nothing to set up. Use it to track prices and discounts, research products and sellers, or watch your competitors on Shopee.

### 📋 What data can you extract from Shopee?

One item per product, 52 fields:

| Category | What you get |
| --- | --- |
| 🏷️ **Product** | name, link, Shopee product, item and shop numbers, market, main photo — `Google Pixel 10a [128GB/256GB]` |
| 💰 **Price and discount** | price (and the highest price when Shopee shows a price range), price before discount, discount, currency, Brazil's Pix price — `778.9 SGD, -13%` |
| ⭐ **Rating and sales** | rating shown in the search results, and whether it is the product's rating or the shop's; units sold when the card shows them — `4.9 (product)`, `3 Sold` |
| 📍 **Location and labels** | where the seller ships from, promotion labels — `SG`, `Selling Fast`, `Free Gift` |
| 🔎 **Where it was found** | the keyword, the search you asked for, the rank on its results page |
| 📦 **Variants** (option) | variation axes and every variant (colour, size…) with its id and pre-order flag — `Lavender, 256GB` |
| 📄 **Product page** (option) | full description, specifications, brand, category path, all photos and videos, listing date, condition, minimum order, wholesale prices |
| 🚚 **Shipping and offers** (option) | days to ship, Shopee Mall shop, fulfilled by Shopee, shop vouchers (code, discount, minimum spend, share already claimed, end date), flash sale end, guarantees — `100% Authentic` |
| 🏪 **Seller profile** (option) | shop name, shop link, shop rating, number of shop ratings, followers — `Google Authorised Retailer, 4.9, 20,400 followers` |

Every field, with an example, is listed in the **Output** section below.

The rows marked (option) are filled when you tick **Full product details** (variants, product page, shipping and offers) or **Seller profile**. Both are paid options, off by default; without them those columns are `null`. Everything else comes with the search itself.

### ✅ Why use Shopee Product Scraper?

- 🌏 **8 Shopee markets in one Actor**: Singapore, Malaysia, Philippines, Thailand, Vietnam, Indonesia, Taiwan and Brazil, each price in the market's own currency.
- 📈 **More than the first 40 products**: a Shopee search shows about 40 products and no real page 2. **Deep search** reads the same search again in every sort order and in narrower and narrower price bands, for hundreds of products per keyword (keyword searches and search URLs; a category page gives its first 24 products).
- ⭐ **Product rating or shop rating?** In some markets the search results show the shop's rating instead of the product's. The `ratingType` column tells you which one you got, and **Min rating** only keeps real product ratings.
- 📦 **Variants and offers** (option): every colour and size, plus shop vouchers, flash sale end and guarantees.
- 🏪 **Seller profile** (option): shop rating, number of ratings and followers, read once per seller and copied to all its products.
- 🧩 **Nothing missed, nothing twice**: a product found by several searches or sort orders is saved — and charged — once.
- 🔔 **Monitoring built in**: tick **Only new products**, schedule the Actor, and each run returns (and charges) only what it has never delivered before.
- 🔌 API, scheduling, monitoring, integrations (Make, Zapier, n8n, Google Sheets…), proxy rotation and JSON/CSV/Excel export via the Apify platform.

### 🚀 How to scrape Shopee

1. Create a free Apify account.
2. Open **Shopee Product Scraper**, choose the **Market** and type a **Search keyword** (e.g. `iphone 15`).
3. Or paste Shopee links into **Start URLs**: search results (the sort, price range, location and Shopee Mall filters set on the site are kept), category pages, shops or single products, from any of the 8 markets. A category page shows only the name, price and photo of each product (no discount or location; a rating in Brazil only), and a shop page shows no price before discount: those columns are then `null` (with **Full product details**, the seller location comes from the product page).
4. Set **Max products** (100 by default, 0 = no limit) — and **Max products per search** when you run several searches — then click **Start**.
5. Download the dataset in JSON, CSV, Excel or via API.

### 💰 How much does it cost to scrape Shopee?

This Actor uses **pay per event** pricing: you pay for each product returned, plus a small fee per run start. The options are off by default, charged apart and only for what they deliver. See the **Pricing** tab for every amount.

- **Product**: each product saved from a search, category or shop page.
- **Product with details** (**Full product details**): each product saved after its product page was read, charged instead of the product price, not on top of it. The filters **Condition**, **Brand**, **Products with a video only** and **Wholesale offers only** need the product page, so they turn the details on. A product link pasted in **Start URLs** is always read on its page and is charged as a product with details.
- **Seller profile** (**Seller profile**): once per seller found in the run, on the first product of that seller; the seller's other products carry the same profile at no extra charge. A shop that gives no profile is not charged.
- **Filter check** and **Detail filter check**: the filters Shopee does not offer are applied by the Actor on every product it reads (**Min rating**, **Discounted products only**, **Exclude keywords**, and the price range checked again on each product). A product that passes costs its normal price; a product a filter drops costs a small filter fee instead, so filtering never costs more than taking everything. Detail filter check is the fee of a product dropped after its page was read (**Condition**, **Brand**, video, wholesale). With **Only new products**, a product your filters drop is checked (and the fee charged) once; the next runs with the same filters skip it for free. Change a filter, or tick **Reset the memory**, to check them again. **Official shops only** and the seller location are Shopee's own filters: they cost nothing extra.

**Deep search** does not change the price per product. Platform usage (compute, proxy) is included in the price.

### ⚙️ Input

```json
{
    "country": "SG",
    "query": "iphone 15",
    "maxItems": 200
}
```

Several searches in Brazil, a cap per search, filters, and only the products not delivered before:

```json
{
    "country": "BR",
    "searchQueries": ["fone bluetooth", "smartwatch"],
    "location": "São Paulo",
    "maxItems": 500,
    "maxItemsPerQuery": 100,
    "minRating": 4.5,
    "discountedOnly": true,
    "onlyNew": true,
    "stateKey": "br-audio"
}
```

Or with your own links, with both options:

```json
{
    "startUrls": [
        { "url": "https://shopee.sg/search?keyword=iphone&minPrice=500" },
        { "url": "https://shopee.co.id/Laptop-cat.11044364.11044440" },
        { "url": "https://shopee.sg/shop/454919755" },
        { "url": "https://shopee.sg/Google-Pixel-10a-128GB-256GB--i.454919755.44228667447" }
    ],
    "extractDetails": true,
    "includeShopProfile": true,
    "maxItems": 300
}
```

| Field | Notes |
| --- | --- |
| `country` | Market searched by the keywords: `SG` (default), `MY`, `PH`, `TH`, `VN`, `ID`, `TW`, `BR`. Start URLs carry their own market. |
| `query`, `searchQueries` | Product search, exactly as typed on Shopee (`iphone 15`); `searchQueries` adds more keywords (one search each). Ignored when `startUrls` is set. |
| `location`, `locations` | Seller location, written as Shopee's location filter lists it for that market (`Singapore` or `Mainland China` in Singapore, `Jakarta Barat` in Indonesia, `São Paulo` in Brazil) — not the `location` column of the results — sent to Shopee's location filter; `locations` adds more places. Every keyword is searched in every location (max 500 searches per run). |
| `startUrls` | Search results (`https://shopee.sg/search?keyword=iphone&minPrice=500`), category pages (`https://shopee.co.id/Laptop-cat.11044364.11044440`), shops (`https://shopee.sg/shop/454919755`) or single products (`https://shopee.sg/product/454919755/44228667447`), from any of the 8 markets. Max 1,000 URLs. |
| `maxItems` | Stop after this many products for the whole run, after deduplication and filters (`0` = unlimited). |
| `maxItemsPerQuery` | Cap for EACH search (keyword × location, or start URL). `0` = no per-search cap. |
| `sort`, `deepSearch` | Shopee sort order: `relevance` (default), `best_selling`, `newest`, `price_low_to_high`, `price_high_to_low`. It orders the page of about 40 products Shopee gives for the search, picked among its top results: not a ranking of all of Shopee (`price_low_to_high` with `maxItems` 15 gives the 15 cheapest of that page, not the 15 cheapest on Shopee). `deepSearch` (on by default) also reads the other orders and narrower price bands to reach more products, only when your cap asks for more than the first page gives (or with no cap); the sort chosen here is read first. Keyword searches only: a start URL keeps its own filters. |
| `minPrice`, `maxPrice` | Price range in whole units of the market's currency (`500`), sent to Shopee and checked on each product. Also added to a pasted search URL that has no price bound of its own. |
| `condition` | `any` (default), `new` or `used`. Read on the product page: turns on the details. |
| `officialShopOnly` | Only Shopee Mall / official brand stores (Shopee's own filter). Keyword searches only: a start URL keeps its own filters. |
| `extractDetails` | Paid option: open each product page for every variant, description, specifications, brand, category path, all photos and videos, listing date, shipping days and vouchers. |
| `includeShopProfile` | Paid option: add the seller's shop name, shop rating, number of shop ratings and followers to each product (charged once per seller per run). |
| `minRating` | Only products whose product rating is at least this value (`4.5`). Products with no product rating (new, or only a shop rating shown) are dropped. |
| `discountedOnly` | Only products showing a discount. |
| `brand` | Only products of this brand, as written on the product page, case ignored (`Samsung`). Turns on the details. |
| `withVideoOnly`, `wholesaleOnly` | Only products with a video, or with wholesale prices. Read on the product page: each turns on the details. |
| `excludeKeywords` | Drop the products whose name contains one of these words (`refurbished`), case and accents ignored. Max 50 words. |
| `onlyNew`, `stateKey`, `resetState` | Monitoring: only the products never delivered under this memory key (`sg-iphone`); `resetState` forgets the memory. |
| Advanced | `proxyConfiguration` (Apify proxy by default, included in the price; the residential Apify proxy is not available), `maxConcurrency`, `maxRequestsPerMinute`, `minRequestIntervalMs`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

One real product with both options on (shortened: 7 more photos and 4 more variants):

```json
{
    "id": "454919755.44228667447",
    "itemId": "44228667447",
    "shopId": "454919755",
    "url": "https://shopee.sg/Google-Pixel-10a-128GB-256GB--i.454919755.44228667447",
    "title": "Google Pixel 10a [128GB/256GB]",
    "country": "SG",
    "price": 778.9,
    "priceMax": null,
    "priceBeforeDiscount": null,
    "discountPercent": 13,
    "priceIsPix": null,
    "currency": "SGD",
    "rating": 4.9,
    "ratingType": "product",
    "sold": null,
    "location": "SG",
    "labels": ["Selling Fast", "Free Gift"],
    "image": "https://down-sg.img.susercontent.com/file/sg-11134301-8259q-mtrcwmkwf0g320",
    "images": [
        "https://down-sg.img.susercontent.com/file/sg-11134301-8259q-mtrcwmkwf0g320",
        "https://down-sg.img.susercontent.com/file/sg-11134301-8257t-mtrcv29rpuyt57"
    ],
    "displayModelId": "340542500967",
    "searchQuery": "iphone",
    "searchUrl": "https://shopee.sg/search?keyword=iphone",
    "position": 11,
    "brand": "Google",
    "brandId": "1146548",
    "categoryId": "11013454",
    "categories": ["Mobile & Gadgets", "Mobile Phones & Tablets", "Google"],
    "description": "Google Pixel 10a [128GB/256GB]\nGoogle Pixel 10a [128GB/256GB]",
    "attributes": [
        { "name": "Brand", "value": "Google" },
        { "name": "Ships From", "value": "SG" }
    ],
    "variations": [
        { "name": "Colour", "options": ["Obsidian", "Fog", "Lavender"] },
        { "name": "Size", "options": ["128GB", "256GB"] }
    ],
    "variants": [
        { "modelId": "340542500970", "name": "Lavender,256GB", "stock": null, "isPreOrder": false },
        { "modelId": "340542500965", "name": "Obsidian,128GB", "stock": null, "isPreOrder": false }
    ],
    "stock": null,
    "condition": "new",
    "itemStatus": "normal",
    "isPreOrder": false,
    "createdAt": "2026-02-09T02:13:16.000Z",
    "isOfficialShop": true,
    "isServiceByShopee": true,
    "estimatedShippingDays": 1,
    "minPurchaseLimit": 1,
    "wholesaleTiers": [],
    "videos": [],
    "shopVouchers": [
        {
            "code": "SFC-1511244646195200",
            "promotionId": "1511244646195200",
            "discount": 20,
            "minSpend": 0,
            "percentUsed": 10,
            "startsAt": "2026-09-30T16:00:57.000Z",
            "endsAt": "2026-10-31T15:59:57.000Z"
        }
    ],
    "flashSaleEndsAt": "2026-10-15T04:00:00.000Z",
    "services": [
        "100% Authentic",
        "Fulfilled by Shopee",
        "15-Day Free Returns",
        "Extended Warranty",
        "Electronics Protection"
    ],
    "shopName": "Google Authorised Retailer",
    "shopUsername": "google.authorisedretailer",
    "shopUrl": "https://shopee.sg/google.authorisedretailer",
    "shopRating": 4.9,
    "shopRatingCount": 13373,
    "shopFollowers": 20400,
    "scrapedAt": "2026-10-15T12:00:00.000Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel.

#### All 52 fields

| Fields | What you get |
| --- | --- |
| `id`, `itemId`, `shopId` | 🏷️ **Product** — `454919755.44228667447` (shop number . item number, unique across Shopee), `44228667447`, `454919755` |
| `url`, `title`, `country` | product page, product name, market (`SG`, `MY`, `PH`, `TH`, `VN`, `ID`, `TW`, `BR`) |
| `price`, `priceMax`, `priceBeforeDiscount`, `discountPercent`, `priceIsPix`, `currency` | 💰 **Price** — `778.9`; for a price range (`S$20 - S$90`) `price` is the lowest and `priceMax` the highest; struck-through price; `13` for -13%; `true` when the Brazilian price is the Pix price; `SGD` |
| `rating`, `ratingType`, `sold` | ⭐ **Rating and sales** — `4.9`; `product` or `shop` (the card showed the shop's rating); units sold when the card prints them (`3 Sold` = `3`, `1.2k sold` = `1200`), `null` otherwise: Shopee shows this count to visitors who are not logged in on few cards only |
| `location`, `labels` | ships from (`SG`, `Mainland China`), promotion labels (`Selling Fast`, `Free Gift`) |
| `image`, `images`, `displayModelId` | main photo, every photo (main photo only without details), the variant whose price is shown |
| `searchQuery`, `searchUrl`, `position` | the keyword, the search you asked for (keyword search, category or shop link), the rank on the results page of that search (`1` = first); `position` is `null` for a product deep search found by reading the search again in another order or price band |
| `brand`, `brandId`, `categoryId`, `categories` | **details** — `Google`, category path `Mobile & Gadgets` › `Mobile Phones & Tablets` › `Google` |
| `description`, `attributes` | **details** — full description, specifications (name / value pairs) |
| `variations`, `variants`, `stock`, `isPreOrder` | **details** — variation axes (`Colour`: `Obsidian`, `Fog`, `Lavender`), each variant with its id, name and pre-order flag; `stock` and `variants[].stock` stay `null` while Shopee hides the stock from visitors who are not logged in |
| `condition`, `itemStatus`, `createdAt` | **details** — `new` or `used`, listing status `normal`, listing date `2026-02-09T02:13:16.000Z` |
| `isOfficialShop`, `isServiceByShopee`, `estimatedShippingDays`, `minPurchaseLimit`, `wholesaleTiers` | **details** — Shopee Mall shop, fulfilled by Shopee, days before shipping, minimum order quantity, quantity prices |
| `videos`, `shopVouchers`, `flashSaleEndsAt`, `services` | **details** — video links, shop vouchers (code, discount, minimum spend, share already claimed, start and end), flash sale end, guarantees (`100% Authentic`, `15-Day Free Returns`) |
| `shopName`, `shopUsername`, `shopUrl`, `shopRating`, `shopRatingCount`, `shopFollowers` | **seller profile** — `Google Authorised Retailer`, `google.authorisedretailer`, shop link, `4.9`, `13373` shop ratings, `20400` followers (`20.4k` on Shopee) |
| `scrapedAt` | ISO timestamp of the extraction |

### 💡 Tips

#### How to get more results

Keep **Deep search** on (default), set `maxItems` to `0` and use a broad keyword. Without deep search, each search gives about 40 products: Shopee shows about 40 products per search and no real page 2. Deep search works on keyword searches and search URLs; a category page gives its first 24 products and a shop URL returns the products its shop page shows, not the whole catalogue. To cover a large market, split it by price with `minPrice` / `maxPrice`, or run several keywords at once.

#### How to reduce costs

The price is per product, so the levers are `maxItems`, `maxItemsPerQuery`, the filters (a filtered-out product costs only the filter fee, lower than a product) and `onlyNew` for recurring runs (you never pay twice for the same product). Tick **Full product details** only when you need the variants, description or vouchers: the filters **Condition**, **Brand**, **Products with a video only** and **Wholesale offers only** turn it on too. **Official shops only**, the seller location and the price range are sent to Shopee itself.

#### Several searches in one run

Fill `searchQueries` and / or `locations`: the Actor runs one search per keyword × location (3 keywords × 4 locations = 12 searches, up to 500 per run). The single `query` and `location` fields still work and are added to the lists. A product found by several searches is saved — and charged — once. Set `maxItemsPerQuery` to give every search its own cap: without it the first searches can use up the whole `maxItems` budget. You can also paste several Shopee links into `startUrls`: each one is a search of its own, with the same cap.

#### Product rating or shop rating

In the search results, Shopee usually shows the product's rating. In some markets (Singapore, the Philippines, Indonesia, Brazil) a card may show the **shop's** rating instead, labelled as such on Shopee ("Shop Rating", "Penilaian Toko", "Avaliação da loja"). The Actor keeps the number in `rating` and tells you which one it is in `ratingType` (`product` or `shop`). **Min rating** only keeps products whose own rating reaches your value: a card that only shows a shop rating is dropped. For the shop's full profile (rating, number of ratings, followers), tick **Seller profile**.

#### Monitoring: only the new products

Tick **Only new products** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips the products already delivered: they are not saved, not charged, and their page is not even opened. The memory lives in a named key-value store of your account (`shopee-product-scraper-seen`, up to 150,000 products per key) and is only updated with products that really reached the dataset, so a failed run never hides anything. Give each schedule its own `stateKey` (two schedules sharing a key would hide each other's products), and tick `resetState` once to start over. Shopee shows no publication date in its search results, so each run reads its searches again and keeps only the products it has not delivered yet.

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run. It returns one item per Shopee product. Actor id: `nice_dev/shopee-product-scraper`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/shopee-product-scraper`.

Smallest input, for a cheap first call:

```json
{
    "country": "SG",
    "query": "iphone",
    "maxItems": 10
}
```

Key output fields: `url`, `title`, `price`, `currency`, `discountPercent`, `rating`, `location`, and `variants` (with `extractDetails`).

Cost: a price per product plus a small fee per run start; the details and the seller profile are options charged apart (see the pricing section above and the **Pricing** tab). Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

#### Is it legal to scrape Shopee?

The Actor only reads what Shopee shows publicly to any anonymous visitor. It logs in to nothing. Results are product and shop data; a shop name can be a person's name, which is personal data protected by GDPR and similar laws: do not store it without a legitimate reason. You are responsible for using the data in compliance with Shopee's Terms of Service and applicable law. This Actor is not affiliated with Shopee.

#### Does it need a login or a proxy?

No login. The proxy is included in the price, product pages included: leave the default setting (the residential Apify proxy is not available). A request the site turns away is retried at once on a new proxy session, up to 10 times on top of the retries (without a proxy, after a pause of 5 seconds, doubled at each retry up to 150 seconds).

#### Why are there no reviews, and units sold on few products only?

Shopee shows customer reviews, the units sold of most products and the product page's price and rating only to visitors who are logged in. The Actor logs in to nothing, so customer reviews are not available, and `sold` is filled only when the search card itself prints the count (`3 Sold`: about 1 card in 40 in Singapore), `null` otherwise. Price, discount and rating come from the search results instead; a product link pasted alone in **Start URLs** has no search result behind it, so its `price`, `discountPercent` and `rating` are `null`.

#### Is the data safe to open in Excel or to show on a web page?

Product names and descriptions are the sellers' own words, copied as they are. A text can begin with `-`, `+`, `=` or `@` (a name such as `-50% today`): Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. On a web page, escape every field like any text written by a stranger.

#### Known limitations

- Customer reviews are not available, and units sold only for the few products whose search card shows them (see above).
- The sort order applies to the page of about 40 products Shopee gives for a search, not to all of Shopee: `price_low_to_high` does not return the cheapest products of the whole market. To narrow a market, set `minPrice` / `maxPrice`.
- Shopee shows no publication date in its search results: there is no date filter. The listing date (`createdAt`) comes with **Full product details**.
- A shop URL returns the products its shop page shows, not the whole catalogue, and a category page its first 24 products; deep search works on keyword searches and search URLs.
- Shopee hides the stock from visitors who are not logged in (it shows the same placeholder on every variant): `stock` and `variants[].stock` stay `null`.
- `onlyNew` remembers product numbers, not their content: a product whose price changed is not returned again.
- Two runs sharing the same `stateKey` at the same time may both return the same new product.

**A run that reaches its timeout** stops itself about 45 seconds before it: no new page is asked, what it read is saved and, with `onlyNew`, remembered, and the run ends *Succeeded* with "Stopped before the run's timeout". Resurrect it to go on from there, or give the next run a longer timeout (Run options).

**A run the platform stops without warning** (out of memory)

- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the products already saved are skipped: none is delivered or charged twice, and `maxItems` still counts them.
- With `onlyNew`, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the products it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the products of its last 2 seconds once more.

#### Something doesn't work?

The last line of the log counts the products saved, filtered out and no longer on Shopee (a pasted product link of a removed product, or a product removed while the run was reading it), and the requests that failed after every retry. Those requests and the removed products are listed, with the reason, in the `FAILED_REQUESTS` record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause: a search, category or shop link that does not exist says "Search URL not found", instead of "run it again".

If Shopee changes its pages, you are told instead of paying for blank rows. A results page that shows products but none the Actor can read is an error (listed in `FAILED_REQUESTS`), never a quiet empty result. If the first 20 products read all lack their name or — for products found in search results — their price or photo, the run saves nothing more, stops and fails, and its last message names the missing field: at most those first products are charged. A product that **Min rating** drops because it shows no rating at all counts among those 20. A run of fewer products (a scheduled `onlyNew` run that finds a few new ones, a small **Max products**) is checked at its end, from 5 products: its products are already saved, and the run fails with the missing field instead of ending green.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which URLs failed and why.

# Actor input Schema

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

Shopee URLs from any of the 8 markets: search results (`https://shopee.sg/search?keyword=iphone&minPrice=500`, the filters set on the site are kept), category pages (`https://shopee.co.id/Laptop-cat.11044364.11044440`), shops (`https://shopee.sg/shop/454919755`) or single products (`https://shopee.com.br/...-i.1653322439.58213403669`). The market is read from each URL. When this list is not empty, the keyword fields below are ignored; filters, caps and monitoring still apply. Max 1 000 URLs.

## `country` (type: `string`):

Shopee market searched by the keywords below (start URLs carry their own market).

## `query` (type: `string`):

Product search, exactly as typed on Shopee (e.g. `iphone 15`).

## `searchQueries` (type: `array`):

Several keywords in one run: one search per keyword (times each location below). Added to **Search keyword**; products found by several searches are saved once.

## `location` (type: `string`):

Seller location, written as Shopee's location filter lists it for the market (e.g. `Singapore` or `Mainland China` in Singapore, `Jakarta Barat` in Indonesia, `São Paulo` in Brazil), not the `location` column of the results. Sent to Shopee's own location filter. Empty = everywhere.

## `locations` (type: `array`):

Several seller locations in one run: every keyword is searched in every location (3 keywords × 4 locations = 12 searches, max 500). Added to **Ships from**.

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

Maximum number of products to save for the whole run (after deduplication and filters). 0 = no limit.

## `maxItemsPerQuery` (type: `integer`):

Cap for EACH search (keyword × location, or start URL), so that the first search cannot use up the whole **Max products** budget. 0 = no per-search cap.

## `sort` (type: `string`):

Shopee sort order. It orders the page of about 40 products Shopee gives for the search, picked among its top results: not a ranking of all of Shopee (Price: low to high gives the cheapest products of that page, not of the whole market). With **Deep search** on, the Actor also reads the other orders and price bands when your cap asks for more products than one page gives; the sort chosen here is read first. Keyword searches only: a start URL keeps its own filters.

## `deepSearch` (type: `boolean`):

Shopee shows about 40 products per search page and no real page 2. On: the Actor re-reads the search with every sort order and with narrower and narrower price bands until no new product comes up (hundreds of products per keyword). Off: one page per search (about 40 products, fastest). Same price per product either way.

## `minPrice` (type: `integer`):

Lowest price, in the market's currency (SGD, IDR, BRL…), whole units. Sent to Shopee and checked on each product.

## `maxPrice` (type: `integer`):

Highest price, in the market's currency, whole units. Sent to Shopee and checked on each product.

## `condition` (type: `string`):

New or used products. Read on the product page: choosing New or Used turns on Product details (the details fee applies) and drops the other products (filter fee).

## `officialShopOnly` (type: `boolean`):

Only products sold by Shopee Mall / official brand stores, the shops behind Shopee's 100% Authentic guarantee (Shopee's own filter). Keyword searches only: a start URL keeps its own filters.

## `extractDetails` (type: `boolean`):

Open each product page for: every variant (id, name, pre-order), full description, specifications, brand, category path, all photos and videos, creation date, shipping days, vouchers. Charged per product delivered with details (see Pricing). Shopee hides prices, units sold and ratings on product pages for visitors who are not logged in: those come from the search card.

## `includeShopProfile` (type: `boolean`):

Add the seller's shop name, shop rating, number of shop ratings and followers to each product (one shop page read per seller, charged once per seller per run).

## `minRating` (type: `number`):

Only products whose product rating (1-5) is at least this value. Products without a product rating (new, or only a shop rating shown) are dropped.

## `discountedOnly` (type: `boolean`):

Only products showing a discount.

## `brand` (type: `string`):

Only products of this brand (as written on the product page, case ignored). Read on the product page: turns on Product details.

## `withVideoOnly` (type: `boolean`):

Only products whose page has a video. Read on the product page: turns on Product details.

## `wholesaleOnly` (type: `boolean`):

Only products with wholesale (quantity) prices. Read on the product page: turns on Product details.

## `excludeKeywords` (type: `array`):

Drop the products whose name contains one of these words (case and accents ignored).

## `onlyNew` (type: `boolean`):

Skip the products that a previous run (same **Memory key**) already delivered: they are not saved and not charged, and their page is not even opened. First run = everything is new.

## `stateKey` (type: `string`):

Name of the memory used by **Only new products**. Give each schedule / task its own key (e.g. `sg-iphone`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every product again. Untick it afterwards.

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

Apify Proxy or your own proxies, used for search, category and shop pages. Keep the default: it is included in the price. Product details always go through our own residential proxy in the product's country (included in the details price). The residential Apify proxy is not available in this Actor.

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

Maximum number of requests processed in parallel.

## `maxRequestsPerMinute` (type: `integer`):

Most requests to the site in any 60 seconds, all of them counted: search pages, shop pages and product pages. A budget, not an even pace: up to this many can leave at once when the minute starts (spread them with the minimum delay below). Lower it if the site answers HTTP 429 / 403 in the log.

## `minRequestIntervalMs` (type: `integer`):

Smallest gap between two requests, in milliseconds. Unlike the per-minute rate, this spreads the requests evenly instead of letting them go out in a burst. 0 = no gap.

## `maxRequestRetries` (type: `integer`):

Retries per request before it is marked as failed. Behind a proxy, a request the site turns away is also retried on a new proxy session up to 10 times without using up these retries.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "startUrls": [],
  "country": "SG",
  "query": "iphone",
  "searchQueries": [],
  "locations": [],
  "maxItems": 100,
  "maxItemsPerQuery": 0,
  "sort": "relevance",
  "deepSearch": true,
  "condition": "any",
  "officialShopOnly": false,
  "extractDetails": false,
  "includeShopProfile": false,
  "discountedOnly": false,
  "withVideoOnly": false,
  "wholesaleOnly": false,
  "excludeKeywords": [],
  "onlyNew": false,
  "stateKey": "default",
  "resetState": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 8,
  "maxRequestsPerMinute": 120,
  "minRequestIntervalMs": 0,
  "maxRequestRetries": 5,
  "debugLog": false
}
```

# Actor output Schema

## `results` (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 = {
    "query": "iphone",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nice_dev/shopee-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 = {
    "query": "iphone",
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("nice_dev/shopee-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 '{
  "query": "iphone",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call nice_dev/shopee-product-scraper --silent --output-dataset

```

## MCP server setup

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