# JD.com Product & Reviews Scraper (`khadinakbar/jd-com-product-reviews-scraper`) Actor

Scrape JD.com (京东 / Jingdong) product details and customer reviews by product URL or SKU. Returns title, price, shop, stock, images, and review text/ratings. Cookieless HTTP Impit + managed review recovery. MCP-ready.

- **URL**: https://apify.com/khadinakbar/jd-com-product-reviews-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** E-commerce, MCP servers, Automation
- **Stats:** 3 total users, 3 monthly users, 80.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 product scrapeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

Scrape **public JD.com (京东 / Jingdong) product details and customer reviews** by product URL or numeric SKU. Paste `item.jd.com/{sku}.html` links (or mobile product URLs) and get flat dataset rows for title, brand, price when JD exposes it, shop, stock signals, images, and optional review text with ratings — built for China ecommerce researchers, price-monitoring teams, and AI agents on Apify.

### What data can you extract from JD.com?

One dataset row per product or review, with provenance on every item.

| Field | Description |
|---|---|
| `recordType` | `product` or `review` |
| `skuId` / `productId` / `title` / `brand` / `productUrl` | Product identity |
| `price` / `priceDisplay` / `priceMasked` / `currency` | CNY price when JD exposes it; `priceMasked` flags hidden prices |
| `shopId` / `shopName` / `stockStatus` / `imageUrl` | Offer and media signals |
| `reviewId` / `content` / `rating` / `userNickname` / `createdAt` | Customer review fields |
| `source` / `scrapedAt` | Provenance and freshness |

### Best fit

Use this Actor when you already have JD product URLs or SKU IDs and need structured product rows and optional customer reviews for monitoring, assortment research, or MCP/agent pipelines. It stays focused on mainland JD.com product pages you supply — keyword search and shop catalogs are a different workflow.

### Related next step

When you need Alibaba.com B2B listing cards instead of JD SKUs, route to [Alibaba Listings Scraper](https://apify.com/khadinakbar/alibaba-listings-scraper). For AliExpress search and product detail, use [AliExpress All-in-One Scraper](https://apify.com/khadinakbar/aliexpress-all-in-one-scraper). For Amazon catalog intelligence after a China-market pull, continue with [Amazon Product Intelligence](https://apify.com/khadinakbar/amazon-product-intelligence).

### Workflow story

A sourcing analyst pastes one hoodie SKU URL, sets `mode` to `product+reviews`, `maxReviewsPerProduct` to `5`, and keeps Residential proxy on. The run returns one product row plus up to five review rows. She exports JSON for a weekly price-and-sentiment sheet, notes any `priceMasked: true` SKUs as price-unavailable, and schedules the same input for monitor-style checks.

### How it works

1. Normalizes `item.jd.com` / `item.m.jd.com` URLs and bare numeric SKUs
2. Fetches the mobile product page over HTTP (Impit Chrome-TLS) and parses embedded `window._itemOnly` catalog fields
3. Optionally collects public customer reviews (native club path, then managed recovery when configured)
4. Deduplicates SKUs, charges named PPE events, and writes product and review rows to the dataset
5. Writes `OUTPUT` and `RUN_SUMMARY` with outcome, counts, and charged events

### Input example

```json
{
  "productUrls": [{ "url": "https://item.jd.com/100066291366.html" }],
  "mode": "product+reviews",
  "maxProducts": 1,
  "maxReviewsPerProduct": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

| Field | Type | What it controls |
|---|---|---|
| `productUrls` | array | `item.jd.com` or `item.m.jd.com/product` URLs |
| `skuIds` | array | Bare numeric SKU IDs |
| `mode` | enum | `product`, `reviews`, or `product+reviews` |
| `maxProducts` | integer | Cap on distinct SKUs (default 10) |
| `maxReviewsPerProduct` | integer | Cap on reviews per SKU (default 20) |
| `preferManagedReviews` | boolean | Prefer managed review recovery first |
| `proxyConfiguration` | object | Recommended Apify Residential |

### Example output

```json
{
  "recordType": "product",
  "skuId": "100066291366",
  "title": "回力卫衣男秋季长袖t恤简约圆领休闲运动跑步健身上衣套头衫男装",
  "brand": "回力",
  "currency": "CNY",
  "shopName": "示例店铺",
  "stockStatus": "in_stock",
  "productUrl": "https://item.jd.com/100066291366.html",
  "source": "mobile_pdp",
  "scrapedAt": "2026-09-30T10:00:00.000Z"
}
```

You can download the dataset as JSON, CSV, Excel, or HTML. Every run also writes `OUTPUT` and `RUN_SUMMARY`.

### Pricing

This Actor uses **Pay per event** with **platform usage** passed through to the caller. Current event prices:

- `apify-actor-start`: $0.00005 per run
- `product-scraped`: $0.005 per validated product row (primary)
- `review-scraped`: $0.012 per validated review row

For example, one product with five review rows costs about $0.065 in named events plus small platform usage. Only validated product and review rows receive those named charges. Treat the **live Pricing tab** on the Actor page as the current source of truth for event prices and platform usage before budgeting a production run.

### Outcomes

Every run writes `OUTPUT` and `RUN_SUMMARY` with one of:

`COMPLETE` | `PARTIAL` | `VALID_EMPTY` | `INVALID_INPUT` | `UPSTREAM_FAILED` | `CONFIG_ERROR`

- `PARTIAL`: products saved while reviews stayed empty (or the reverse under review-only mode)
- `INVALID_INPUT`: no usable URLs or SKUs after normalization
- `UPSTREAM_FAILED`: JD did not return usable data and nothing billable was saved

### API example

```bash
curl -X POST "https://api.apify.com/v2/acts/khadinakbar~jd-com-product-reviews-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"productUrls":[{"url":"https://item.jd.com/100066291366.html"}],"mode":"product","maxProducts":1}'
```

Then read the dataset and the `OUTPUT` record for outcome, row counts, and charged events.

### MCP / agent prompt card

> Scrape JD.com product `https://item.jd.com/100066291366.html` for title, price (note if masked), shop, stock, and up to 5 customer reviews. Tool: `khadinakbar/jd-com-product-reviews-scraper`. Return flat rows with `skuId` and `recordType`. Cost is $0.005 per product row and $0.012 per review row plus platform usage.

### Tips for best results

- Prefer Chinese-market SKUs on `item.jd.com` (mainland product pages)
- Start with `maxProducts: 1` and `maxReviewsPerProduct: 5` for a cheap quality check
- When `priceMasked` is true, treat price as unavailable and keep the display string for audit
- Keep Apify Residential enabled for steadier mobile PDP yield

### Builder's note

I built this Actor after probing JD's desktop PDP from outside China and finding a risk-control shell instead of catalog HTML. The mobile product page (`item.m.jd.com`) still embeds `window._itemOnly` with usable title, shop, stock, and image fields, so the runtime is cookieless Impit against that path. Public comment JSON often returns a busy response on generic residential exits, so I designed a native club attempt first and a bounded managed review recovery behind an owner token — callers keep Limited permissions and still get review rows when recovery is available.

### Legal / responsible use

Use only on public JD.com pages and data you are authorized to process. Respect JD.com terms, applicable privacy laws, and Apify Store policies. The Actor reads public product and review surfaces only. JD.com / 京东 are trademarks of their respective owners. This independent Actor is not affiliated with, associated with, or endorsed by JD.com.

# Actor input Schema

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

One or more JD product links such as https://item.jd.com/100066291366.html or mobile item.m.jd.com/product/{sku}.html. Combined with skuIds.

## `skuIds` (type: `array`):

Numeric JD SKU IDs from the product URL path. Use when you already have IDs instead of full URLs.

## `mode` (type: `string`):

product = details only. reviews = customer reviews only. product+reviews = both (default).

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

Hard cap on distinct SKUs processed. Prefill 1 keeps quality tests cheap. Maximum 100.

## `maxReviewsPerProduct` (type: `integer`):

When mode includes reviews, cap saved review rows per SKU. Prefill 5 for cheap tests. Maximum 200.

## `preferManagedReviews` (type: `boolean`):

When true, skip the native club.jd.com attempt and go straight to managed review recovery. Leave false unless native comments stay blocked.

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

Recommended: Apify Residential. Product pages often work without a proxy; review recovery may still need Residential.

## Actor input object example

```json
{
  "productUrls": [
    {
      "url": "https://item.jd.com/100012043978.html"
    }
  ],
  "skuIds": [
    "100066291366"
  ],
  "mode": "product+reviews",
  "maxProducts": 1,
  "maxReviewsPerProduct": 5,
  "preferManagedReviews": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Product and/or review rows.

## `output` (type: `string`):

Final outcome, itemsPushed, and chargedEventCounts.

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

Per-job outcomes and billing counters.

# 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": [
        {
            "url": "https://item.jd.com/100066291366.html"
        }
    ],
    "mode": "product+reviews",
    "maxProducts": 1,
    "maxReviewsPerProduct": 5,
    "preferManagedReviews": false,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/jd-com-product-reviews-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": [{ "url": "https://item.jd.com/100066291366.html" }],
    "mode": "product+reviews",
    "maxProducts": 1,
    "maxReviewsPerProduct": 5,
    "preferManagedReviews": False,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/jd-com-product-reviews-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 '{
  "productUrls": [
    {
      "url": "https://item.jd.com/100066291366.html"
    }
  ],
  "mode": "product+reviews",
  "maxProducts": 1,
  "maxReviewsPerProduct": 5,
  "preferManagedReviews": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call khadinakbar/jd-com-product-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/jd-com-product-reviews-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/Hv2FOLqNPZTixwELP/builds/aF5vtYpLOn0ii9A5W/openapi.json
