# Temu Product Scraper & Price Monitor (`luminar/temu-product-scraper-price-monitor`) Actor

Search public Temu products with region-bound coverage, extract exact products and SKUs, create commerce-ready rows, or monitor factual changes.

- **URL**: https://apify.com/luminar/temu-product-scraper-price-monitor.md
- **Developed by:** [Luka](https://apify.com/luminar) (community)
- **Categories:** E-commerce, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 temu product results

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?

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

Search Temu by multiple keywords, collect exact public products and variants, create commerce-ready rows, or monitor factual changes without turning a block into an empty result.

![Temu product rows with nested SKU variants and explicit coverage](https://api.apify.com/v2/key-value-stores/DJgPR6wwS2tIaLDQW/records/temu_product_price_monitor--4daff8ac05012f45-real-public-output.png)

### What it does

Use one Actor for keyword discovery, exact product and SKU extraction, commerce-ready exports, and repeat-run price or product monitoring. Every delivered product is tied to a stable Temu goods ID and a literal keyword match; unrelated products are rejected instead of being returned as results.

### What the Actor returns

The normalized product shape can contain source-published:

- stable `goodsId` / `productId`, canonical URL, title, category, and description;
- current price, original/list price, discount, and source-observed currency;
- rating, reviews, and both raw and normalized sold count with `soldCountIsLowerBound` for values such as `5K+`;
- shop/seller, availability, shipping text, free-shipping flag, and delivery-day bounds;
- primary image, gallery images, product video;
- nested variants with stable SKU ID, label, price, list price, availability, stock, and media.

Every field is nullable when Temu does not publish it. The Actor does not infer demand, “hot product”, trend, risk, value, profit, or recommendations.

Each run also writes:

- an explicit `coverage` row with per-target receipts and exact field coverage;
- an optional free `summary` row with mechanical counts, price statistics, and source-sold-count ordering;
- `change` rows in monitoring mode;
- a sanitized run summary with coverage, state outcome, accepted charge counts, public-source classification, and resource totals.

### Quick start

```json
{
  "workflow": "search_products",
  "searchKeywords": ["wireless earbuds", "usb c hub"],
  "region": "us",
  "sortBy": "relevance",
  "maxProductsPerKeyword": 20,
  "includeVariants": true,
  "outputFormat": "default"
}
```

Keywords run sequentially for the selected market. Products are deduplicated by `goodsId`; variants remain nested, so one product is one result row.

### Three workflows

#### Search products

Use `search_products` with one to ten `searchKeywords`. `maxProductsPerKeyword` accepts 1–300. The permanent keyword-fidelity contract rejects an unrelated recommendation/funnel surface with `WRONG_SURFACE_ZERO_KEYWORD_MATCH`.

Sort choices are:

- `relevance`: preserves Temu source order;
- `top_sales`: mechanical descending normalized source sold count;
- `price_asc` / `price_desc`: mechanical price order;
- `newest`: uses a source-published listing timestamp and fails closed when that field is absent.

`minPrice` and `maxPrice` are deterministic filters. A completed source scope with removed rows is `FILTERED`; that status cannot advance an absence counter toward `ENDED`.

#### Scrape exact products

Use `scrape_exact_products` with up to 100 `productUrls`, 100 bare `productIds`, or both. First-party `*.temu.com` share links are allowed. Redirect-only share links must resolve back to a Temu URL with a stable goods ID; external redirects and unresolved IDs fail closed.

Exact targets read public first-party Temu product data. Detail checks are priced separately from search because they require one public product lookup per target.

#### Track product changes

Use `track_product_changes` with exact public product URLs or IDs and a stable `stateNamespace`.

- First trustworthy run: creates a baseline without a `NEW` flood.
- Later trustworthy run: emits factual `NEW` or `UPDATED` rows with `before`, `after`, and `changedFields`.
- `ENDED`: requires two consecutive comparable complete absences.
- `PARTIAL`, `FILTERED`, `CAPPED`, `BLOCKED`, or `FAILED`: cannot increment the absence counter and cannot prove removal.
- `includeUnchanged: true`: adds current snapshots as free rows.

Run the same namespace and scope sequentially. Controlled repeat-run tests prove quiet baseline creation, factual updates, two-absence `ENDED`, and no duplicate paid change after recovery. A naturally occurring live product change has not yet been observed; universal change coverage is not promised.

### Region presets

The input contains 20 bounded presets: `us`, `uk`, `de`, `fr`, `es`, `it`, `nl`, `au`, `ca`, `br`, `mx`, `jp`, `kr`, `pl`, `se`, `at`, `be`, `pt`, `cz`, and `ie`.

A preset selects the Temu market, language, and **expected** currency. Configuration alone is not field proof: `currencyObserved` becomes true only when the public source publishes the expected currency. Only regions that returned literal keyword matches with matching source-observed currency are listed as supported.

Canary-verified search regions are `us`, `uk`, `de`, `fr`, `es`, `it`, `nl`, `au`, `ca`, `br`, `mx`, `jp`, `pl`, `se`, `at`, `be`, `pt`, `cz`, and `ie`. South Korea (`kr`) is **not yet supported**.

### Output formats and exports

`outputFormat` selects exactly one paid row per factual product:

- `default`: normalized Temu product;
- `shopify`: mechanical Shopify-ready product and nested variant mapping;
- `google_merchant`: mechanical Google Merchant row.

`retailMarkup` is an optional user-supplied multiplier from 1–10. Every derived row labels the transform; the Actor does not recommend a multiplier or claim profitability.

Apify Dataset can export the chosen rows as JSON, CSV, Excel, XML, or RSS. Dataset views cover products, commerce mappings, changes, summaries, and coverage; `recordType` always remains visible because the Dataset contains mixed row types.

### Coverage contract

| Status | Meaning |
|---|---|
| `COMPLETE` | Every requested target completed within the declared comparable scope. |
| `FILTERED` | The source scope completed and buyer price filters removed rows. |
| `CAPPED` | A row, page, request, byte, runtime, or spend guard stopped traversal while more may exist. |
| `PARTIAL` | Useful rows exist, but one or more targets or required layers did not complete. |
| `BLOCKED` | Temu returned a verified block/challenge. This is never empty. |
| `FAILED` | A transport, source-shape, identity, region, or parser failure prevented trustworthy coverage. |
| `EMPTY_CONFIRMED` | The expected source result shape explicitly confirmed no matching rows. |

Supplemental public fields may enrich only goods IDs already present in the keyword-faithful result set. They can never introduce a new product ID.

### Billing contract

The Actor uses four independently priced charge events:

- `search_target`: one trustworthy search target attempt;
- `detail_target`: one trustworthy exact-detail target attempt;
- `monitor_target`: one trustworthy monitoring scan target;
- `product_result`: one atomically delivered product, commerce mapping, or verified change.

The primary product price is the same on every plan: **$1.40 per 1,000 delivered products**. Target-event prices vary by plan:

| Apify tier | Search target | Product result | Detail target | Monitor target |
|---|---:|---:|---:|---:|
| Free | $0.100 | $0.0014 | $0.008 | $0.009 |
| Bronze | $0.100 | $0.0014 | $0.0075 | $0.0085 |
| Silver | $0.100 | $0.0014 | $0.007 | $0.008 |
| Gold | $0.100 | $0.0014 | $0.0065 | $0.0075 |
| Platinum | $0.100 | $0.0014 | $0.006 | $0.007 |
| Diamond | $0.100 | $0.0014 | $0.006 | $0.007 |

A successful search costs one `$0.10` search-target event plus `$0.0014 x delivered products`. For example, 20 products cost `$0.128`, 100 cost `$0.240`, and 300 cost `$0.520` on every plan. A useful exact detail costs one detail-target event plus one product event. An unchanged trustworthy monitoring scan costs only the monitor event; each delivered change adds one product event.

Failed, blocked, unrelated, empty-unconfirmed, and unusable partial targets are free. Coverage, summary, warnings, nested variants, and optional unchanged snapshots are also free rows. `maxBuyerChargeUsd` checks the complete maximum event vector before source work.

### Verified scope and limits

The implementation and canaries verify:

- all three advertised workflows and their buyer-facing input/output contracts;
- 20 preset configurations and independent per-keyword limits through 300;
- strict same-`goodsId` enrichment without admitting unrelated products;
- rich detail normalization and selectable default/Shopify/Google Merchant rows;
- stable product/SKU identity, explicit coverage, quiet monitoring baselines, repeat-safe changes, and bounded maximum state.

**Not yet supported:** South Korea (`kr`) search; guaranteed presence of secondary fields that remain nullable; login/account/cart data; CAPTCHA solving or bypass; alternate third-party source services; inferred scores or recommendations; concurrent writes to the same monitoring scope.

### Safety and source boundaries

The Actor uses anonymous public first-party Temu data only. CAPTCHA or login is a stop condition. A challenge, unrelated result surface, unresolved share link, currency mismatch, or malformed response cannot be billed as a useful product and cannot update monitoring state. The Actor does not place orders or use another scraping Actor as its source.

### Support

For a reproducible issue, include the run ID, sanitized input, region, query or goods ID, and coverage status. Never send credentials, payment data, or 2FA codes.

# Actor input Schema

## `workflow` (type: `string`):

Monitoring creates a quiet baseline, then emits factual NEW, UPDATED, or confirmed ENDED rows after two comparable absences.

## `searchKeywords` (type: `array`):

Up to 10 phrases processed sequentially for the selected market. Keyword-fidelity checks reject unrelated products.

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

Selects the Temu market and expected currency. Currency is reported only when the public source confirms it.

## `sortBy` (type: `string`):

Relevance preserves source order. Price and sales orders are mechanical. Newest fails closed if the source does not publish listing time.

## `maxProductsPerKeyword` (type: `integer`):

Hard ceiling per keyword. Coverage becomes CAPPED if more source rows remain.

## `minPrice` (type: `number`):

Keep rows at or above this source-published price.

## `maxPrice` (type: `number`):

Keep rows at or below this source-published price.

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

Public first-party product URLs and Temu share links. Redirect-only links are resolved without login; non-Temu hosts are rejected.

## `productIds` (type: `array`):

Stable numeric product IDs for exact extraction or monitoring.

## `includeVariants` (type: `boolean`):

Adds source-published SKU IDs, labels, prices, availability, stock, and media when present.

## `outputFormat` (type: `string`):

Selects one mechanical row shape per product. Apify Dataset exports remain available as JSON, CSV, Excel, XML, and RSS.

## `retailMarkup` (type: `number`):

Applied only to commerce prices and labeled in every derived row. The Actor does not recommend a margin or claim profitability.

## `includeSummary` (type: `boolean`):

Adds a free summary row with counts, price statistics, field coverage, and source-sold-count ordering when available.

## `stateNamespace` (type: `string`):

Separates monitoring baselines. Run the same namespace and exact scope sequentially.

## `includeUnchanged` (type: `boolean`):

Monitoring only. Adds unchanged current snapshots as free rows.

## `maxBuyerChargeUsd` (type: `number`):

Work stops before the maximum event vector can exceed this amount.

## `maxRequests` (type: `integer`):

Safety ceiling for public source requests in one run.

## `maxSourceBytes` (type: `integer`):

Safety ceiling for total public source bytes in one run.

## `maxRuntimeSecs` (type: `integer`):

Safety ceiling for source work in one run.

## `maxEstimatedPlatformUsd` (type: `number`):

Safety ceiling checked before starting source work.

## Actor input object example

```json
{
  "workflow": "search_products",
  "searchKeywords": [
    "wireless earbuds"
  ],
  "region": "us",
  "sortBy": "relevance",
  "maxProductsPerKeyword": 20,
  "includeVariants": true,
  "outputFormat": "default",
  "retailMarkup": 1,
  "includeSummary": true,
  "stateNamespace": "default",
  "includeUnchanged": false,
  "maxBuyerChargeUsd": 10,
  "maxRequests": 12000,
  "maxSourceBytes": 1500000000,
  "maxRuntimeSecs": 7200,
  "maxEstimatedPlatformUsd": 1
}
```

# Actor output Schema

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

Open every product, change, and coverage row.

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

Open mixed rows with product columns selected and recordType visible.

## `commerce` (type: `string`):

Open Shopify or Google Merchant mappings with recordType visible.

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

Open source-backed counts, field coverage, price statistics, and sold-count ordering.

## `changes` (type: `string`):

Open mixed rows with change columns selected and recordType visible.

## `coverage` (type: `string`):

Open mixed rows with coverage columns selected and recordType visible.

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

Open the sanitized coverage, state, buyer-charge, public-source, and resource summary.

# 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 = {
    "workflow": "search_products",
    "searchKeywords": [
        "wireless earbuds"
    ],
    "region": "us",
    "sortBy": "relevance",
    "maxProductsPerKeyword": 20,
    "includeVariants": true,
    "outputFormat": "default",
    "retailMarkup": 1,
    "includeSummary": true,
    "stateNamespace": "default",
    "includeUnchanged": false,
    "maxBuyerChargeUsd": 10,
    "maxRequests": 12000,
    "maxSourceBytes": 1500000000,
    "maxRuntimeSecs": 7200,
    "maxEstimatedPlatformUsd": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("luminar/temu-product-scraper-price-monitor").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 = {
    "workflow": "search_products",
    "searchKeywords": ["wireless earbuds"],
    "region": "us",
    "sortBy": "relevance",
    "maxProductsPerKeyword": 20,
    "includeVariants": True,
    "outputFormat": "default",
    "retailMarkup": 1,
    "includeSummary": True,
    "stateNamespace": "default",
    "includeUnchanged": False,
    "maxBuyerChargeUsd": 10,
    "maxRequests": 12000,
    "maxSourceBytes": 1500000000,
    "maxRuntimeSecs": 7200,
    "maxEstimatedPlatformUsd": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("luminar/temu-product-scraper-price-monitor").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 '{
  "workflow": "search_products",
  "searchKeywords": [
    "wireless earbuds"
  ],
  "region": "us",
  "sortBy": "relevance",
  "maxProductsPerKeyword": 20,
  "includeVariants": true,
  "outputFormat": "default",
  "retailMarkup": 1,
  "includeSummary": true,
  "stateNamespace": "default",
  "includeUnchanged": false,
  "maxBuyerChargeUsd": 10,
  "maxRequests": 12000,
  "maxSourceBytes": 1500000000,
  "maxRuntimeSecs": 7200,
  "maxEstimatedPlatformUsd": 1
}' |
apify call luminar/temu-product-scraper-price-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,luminar/temu-product-scraper-price-monitor"
        }
    }
}

```

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/qnqksdshiMNdwqcrG/builds/Gx7KcnWtZKYepJfvd/openapi.json
