# JD Product Scraper: JD.com Prices, Promotions & Shops (`vant47/jd-com-scraper`) Actor

Get JD.com products for tea, phones or clothing keywords and item links: CNY prices, promotion flags, comment counts, shops, barcodes and SKU attributes. $0.0018 per product; 100 cost $0.18. No login. Keep CNY and optional USD conversion for price monitoring.

- **URL**: https://apify.com/vant47/jd-com-scraper.md
- **Developed by:** [fortbrand](https://apify.com/vant47) (community)
- **Categories:** E-commerce, Automation
- **Security:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.44 / 1,000 products

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

## JD Product Scraper: JD.com Prices, Promotions & Shops

For product analysts, sourcing teams, brands and resellers who monitor JD.com listings. Collect public CNY prices, promotion flags, comment counts, shop identities and product links by keyword. Add item details for barcodes, models, images and SKU attributes. A product costs **$0.0018**: 100 distinct products cost **$0.18**, plus the $0.00005 run start fee. No login is needed.

Use one or several Chinese or English product terms, or paste known JD item links. Download the results as JSON, CSV or Excel, or send the dataset to your own price history. The default requests 20 tea products, costing $0.036 plus the start fee when 20 products are delivered. Currency conversion and available item enrichment are included in the product price.

### What you get

| Field | Meaning |
|---|---|
| `summary` | A readable price and shop summary, placed first in each product row |
| `type` | `PRODUCT`, a free `NOTE`, or the free final `SUMMARY` row |
| `itemId`, `url` | JD SKU identifier and canonical desktop product address |
| `title`, `imageUrl` | Product title and public main image |
| `price`, `originalPrice`, `currency` | Numeric public price, original price when supplied, and CNY |
| `priceConverted`, `convertedCurrency` | Additional indicative price in the requested currency |
| `exchangeRate`, `exchangeRateDate`, `exchangeRateSource` | Conversion rate, observation date and provider |
| `shopId`, `shopName`, `venderId` | Shop and vendor identities; the two IDs can differ |
| `isSelfOperated` | Whether JD labels the product as self-operated |
| `reviewCount` | JD's aggregate comment-count text, retaining rounded forms such as `50万+` |
| `reviewCountLowerBound` | Numeric lower bound for the displayed rounded comment count |
| `positiveRatePercent`, `reviewTags` | Aggregate positive rate and public comment tags when supplied |
| `promoTags`, `discountText` | Promotion labels preserved from the public listing |
| `installmentOffer` | Source installment wording such as an interest-free offer |
| `isFlashSale`, `isPresale`, `isBillionSubsidy`, `isLowestPrice` | Explicit source promotion flags, or null when absent |
| `brand`, `model`, `gtin` | Brand, manufacturer model and GTIN with valid length/check digit from item details |
| `sourceBarcode` | Original source UPC field, which can contain nonstandard seller codes |
| `skus` | Available variant IDs, names, colors, sizes and images; price and stock are nullable |
| `specs`, `images` | Available product attributes and image gallery |
| `stockState`, `stockQuantity`, `stockAreaId` | Source stock code, quantity when supplied, and source area |
| `deliveryPromise`, `freeShipping` | Public delivery wording and explicit free-shipping signal |
| `monthlySales`, `shopRating`, `shipFrom` | Stable family fields; null when unavailable |
| `categoryId`, `categoryIds` | Public taxonomy identifiers supplied by JD |
| `sourceQuery`, `sourcePage`, `rank` | Keyword or item ID, search page and source position |
| `sourceUrl`, `priceSourceUrl`, `detailSourceUrl` | Provenance of discovery, price and item metadata |
| `detailLevel`, `missingFields`, `notes` | Coverage and field-level explanations |
| `scrapedAt` | UTC snapshot timestamp |

One product SKU is delivered and charged once per run, even if several keywords find it. Select rows with `type == "PRODUCT"` before loading an export into your product table. Notes and the final summary are useful coverage records and have no product fee.

### Start in three steps

1. Enter a keyword in `searchTerms`, such as `茶叶` for tea, `华为手机` for Huawei phones, or `机械键盘` for mechanical keyboards. Known item URLs can go into `startUrls` instead.
2. Choose `maxItems`. Leave `includeDetails` off for listing prices and shops; enable it for the available barcode, model and variant attributes.
3. Run the Actor, inspect the coverage summary, then export the product rows. Keep CNY amounts and timestamps in any monitoring database.

```json
{
  "searchTerms": ["茶叶"],
  "maxItems": 20,
  "currency": "USD",
  "includeDetails": false
}
```

Chinese terms usually give broader coverage because they match the vocabulary on JD. Other examples are `咖啡` (coffee), `奶粉` (milk powder), `运动鞋` (sports shoes), `手机壳` (phone cases) and `书包` (school bags). English words are sent as entered, without translation.

### Inputs

| Input | Default | Behavior |
|---|---|---|
| `searchTerms` | Empty through the API; Console prefill contains `茶叶` | Array of Chinese or English product terms |
| `startUrls` | Empty | JD product URLs, numeric item IDs or keyword-search URLs |
| `maxItems` | 20 | Total distinct products across all inputs, from 1 to 5,000 |
| `maxItemsPerSearch` | Same as `maxItems` | Optional per-keyword ceiling for spreading a run across several inputs |
| `includeDetails` | false | Adds available public item metadata to search rows; direct item links always read item metadata |
| `sort` | `default` | Source order, `sales`, `priceAsc`, or `priceDesc`; price sorts apply to the collected sample |
| `priceMin`, `priceMax` | No range | Inclusive CNY filters; unknown prices do not pass an active price filter |
| `currency` | USD | Additional conversion currency, such as EUR, GBP, ZAR, HKD or CNY |
| `tmallOnly` | false | Taobao-family compatibility field; true excludes JD products because they are not Tmall listings |
| `proxyConfiguration` | Automatic | Direct cloud datacenter HTTP first, default proxy pool next, then fresh CN/JP residential sessions for refused pages |

`maxItems` is a ceiling. Available source matches, duplicates and filters can reduce the final count. Search collects the public hot-sale listing page by page and stops at its source limit, the requested sample ceiling, or repeated pages with no new IDs. A source refusal produces a note and preserves products already delivered.

```json
{
  "searchTerms": ["茶叶", "咖啡", "奶粉"],
  "maxItemsPerSearch": 100,
  "maxItems": 300,
  "priceMin": 20,
  "priceMax": 1000,
  "currency": "EUR"
}
```

Price filters run against CNY values before delivery. Price ordering is applied to each collected keyword sample, so combining several keywords does not create a globally sorted dataset. `sales` keeps JD source order with an explanatory note.

### Known-item catalog monitoring

Paste desktop or mobile item URLs, or numeric SKU IDs. An item must match the requested ID before it is accepted. Tracking parameters are discarded.

```json
{
  "startUrls": [
    "https://item.jd.com/100320690657.html",
    "https://item.m.jd.com/product/100012043978.html"
  ],
  "maxItems": 2,
  "currency": "CNY"
}
```

Known-item rows are useful for catalog matching: full title, brand, barcode, model, shop, images and variant attributes can be present even when a price is unavailable. Every such delivered product row has the same product fee. Read `missingFields` when deciding whether a snapshot fits your workflow.

For a search row with `includeDetails`, the original search price stays in `price`. `itemPagePrice` records the separately observed item-page value when one exists. This preserves which surface supplied each amount. A refused detail request keeps the search product and adds a note; it does not create a second product charge.

### Example from a live public listing

These selected fields were observed on 4 November 2026. Run again for a fresh snapshot.

```json
{
  "summary": "CNY 128.00; 福茗源京东自营旗舰店; public-search",
  "type": "PRODUCT",
  "itemId": "100016448601",
  "title": "福茗源四大绿茶500g礼盒，品质保证",
  "price": 128,
  "originalPrice": null,
  "currency": "CNY",
  "shopId": "1000225164",
  "shopName": "福茗源京东自营旗舰店",
  "reviewCount": "50万+",
  "reviewCountLowerBound": 500000,
  "positiveRatePercent": 99,
  "monthlySales": null,
  "detailLevel": "public-search",
  "url": "https://item.jd.com/100016448601.html"
}
```

A rounded comment count is not a sales count. Keeping its source text allows an analyst to distinguish an exact value from a lower bound. A missing value is null rather than zero.

### Pricing and spending limits

| Distinct products delivered | Base product charge |
|---:|---:|
| 1 | $0.0018 |
| 20 | $0.036 |
| 100 | $0.18 |
| 1,000 | $1.80 |

The start fee is $0.00005, with Apify's memory-based start-event handling. Bronze gets 5% off the product price, Silver 10%, and Gold and higher tiers 20%. Platform usage is included. The Actor uses no purchased outside data service, and the same functionality is available on the free plan.

Only distinct delivered products incur the product fee. Failed fetches, empty inputs, unsupported URLs, filtered products, duplicate IDs, notes and summaries have no product charge. Public item enrichment and currency conversion have no separate surcharge.

The Actor checks the run's spending limit before requesting more data and before saving a paid product. It stops cleanly when another product cannot fit. Delivery uses a durable dataset ledger and acknowledged charge counts so an interrupted run can continue without repeating a product or its fee. Source snapshots are saved before delivery to preserve the remaining work across a reboot.

### Monitor prices every day

Save the input as an Apify task and attach a daily schedule in Console. Keep the same keyword, filters and detail setting when comparing snapshots. Store `itemId`, CNY price, shop ID, source surface and UTC timestamp. Compare CNY first: the converted amount can change when the exchange rate changes even if the source price does not.

Read the free `SUMMARY` record after each run. It lists delivered products, shops, promotion-bearing rows, input outcomes, free source failures and charged products. A missing product or refused input is a coverage outcome; it is not proof of removal or zero inventory. No schedules are created automatically.

Send completion webhooks to Make, Zapier or n8n, then load the dataset into your own spreadsheet or warehouse. Overview, Shops, Deals, Variants and Coverage views select useful columns; JSON retains nested variant and specification objects.

### API use

Use your own Apify token as an environment secret. The input is the same through Console and the API.

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("vant47/jd-com-scraper").call(
    run_input={"searchTerms": ["机械键盘"], "maxItems": 20}
)
products = [row for row in
            client.dataset(run["defaultDatasetId"]).iterate_items()
            if row.get("type") == "PRODUCT"]
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('vant47/jd-com-scraper').call({
  searchTerms: ['茶叶'], maxItems: 20, currency: 'USD'
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const products = items.filter(row => row.type === 'PRODUCT');
```

### Use with AI agents (MCP)

Connect your client to the [Apify MCP server](https://mcp.apify.com). Ask the agent to inspect `vant47/jd-com-scraper` and its input schema, run a product sample, then explain any missing fields using the coverage summary.

Example request: Get 20 JD tea products using 茶叶. Keep the CNY price, add USD conversion, and include shop names and aggregate comment counts. Explain which optional fields were absent.

For catalog enrichment, give exact item URLs and ask the agent to retain null prices, source URLs and variant identifiers. A useful integration should distinguish `NOTE` rows from products and should not turn a missing value into zero.

### Limits

- Search reads JD's signed-out hot-sale listing. It can contain sponsored placements and semantically related products in JD's own order. A separate general-recommendations block is excluded. It is not a complete export of the main desktop search engine.
- Shop catalog URLs and raw category URLs are not supported. Unsupported links produce free notes. Use descriptive product keywords or known item links.
- JD can mask signed-out item prices. Those prices remain null. Keyword listings supply their own displayed price; account offers, checkout coupons, subsidies and other variants can differ.
- Monthly sales, shop rating scores, ship-from city and per-variant price/stock are unavailable on these routes. Variant IDs and attributes do not establish the inventory of each variant.
- Stock codes, quantities and delivery wording belong to the source default area recorded in `stockAreaId`. There is no customer-selected location input. `inStock` stays null rather than interpreting an undocumented stock code.
- Price sorting applies to the collected keyword sample. Monthly-sales sorting is unavailable. Original prices and promotion dates stay null when JD does not supply them.
- Individual review text, reviewer identities, buyer data, account cookies and login-only content are not collected. The Actor does not solve verification challenges.
- Currency conversion uses a free daily [Frankfurter](https://frankfurter.dev/) rate. If the rate is unavailable or a currency is unsupported, original CNY amounts remain and converted fields are null.

### FAQ

#### Can I use English keywords?

Yes. They are sent as entered. Chinese category words and precise brand/model terms usually align more closely with the source catalog. A broader phrase can produce more products, while a narrow model can produce fewer than the requested limit.

#### Why does an item row have no price?

JD may display a masked price to signed-out visitors. The row can still contain useful catalog data. Check `priceSourceUrl`, `detailLevel` and `missingFields`; use a keyword search when you need the prices shown on public listings.

#### Do I need cookies or a proxy subscription?

No account cookies or outside subscription are needed. Automatic Apify proxy retries are included in the Actor price. A custom proxy configuration is optional. Setting `useApifyProxy` to false disables the automatic proxy fallback and can reduce coverage.

#### Is every SKU in a variant array another paid row?

No. Nested variant identifiers and attributes are included with the product. Only distinct top-level `PRODUCT` rows trigger the fee. The variant price and stock fields remain null unless the source explicitly supplies them.

#### How should I report a problem?

Open an issue with the run ID, input JSON, affected item IDs and the field you expected. Include the source URL and the observed timestamp. Do not attach account cookies or credentials. This is an independent tool for public JD product monitoring and catalog research.

# Actor input Schema

## `searchTerms` (type: `array`):

Chinese or English JD product keywords. Chinese terms generally cover more products.

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

JD item links, numeric SKU IDs or keyword search URLs. Shop and raw category links are skipped with a free note.

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

default and sales keep source order; priceAsc and priceDesc sort each collected keyword sample locally. Monthly sales are unavailable.

## `priceMin` (type: `number`):

Keep source prices at or above this CNY amount. Unknown prices are excluded when a price filter is set.

## `priceMax` (type: `number`):

Keep source prices at or below this CNY amount. Filters run before delivery and excluded products have no product charge.

## `tmallOnly` (type: `boolean`):

Compatibility with the Taobao family. JD products are not Tmall products; true excludes all JD products.

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

Total distinct products across all inputs, up to 5,000. Default 20 products cost $0.036 plus the start fee. The limit is a ceiling; available matches and filters can reduce the count.

## `includeDetails` (type: `boolean`):

Add public item-page barcodes, model, images, SKU attributes and default-area stock codes when available. Variant price/stock remain null. Item URLs always include available details.

## `currency` (type: `string`):

Three-letter currency code, e.g. USD, EUR, GBP, ZAR, HKD or CNY. Daily free Frankfurter rate; keeps the original CNY values and rate date. Conversion failure leaves converted values null.

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

Direct cloud HTTP first, then the account default datacenter proxy pool and fresh CN/JP residential retries for refused pages. Explicit custom proxy groups/URLs are used first. No login cookies.

## `maxItemsPerSearch` (type: `integer`):

Optional ceiling for each keyword. maxItems caps the whole run. Use this to spread a run across several search terms.

## Actor input object example

```json
{
  "searchTerms": [
    "茶叶"
  ],
  "sort": "default",
  "tmallOnly": false,
  "maxItems": 20,
  "includeDetails": false,
  "currency": "USD",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "searchTerms": [
        "茶叶"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("vant47/jd-com-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 = {
    "searchTerms": ["茶叶"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("vant47/jd-com-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 '{
  "searchTerms": [
    "茶叶"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call vant47/jd-com-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vant47/jd-com-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/6NQR5ZKingbwIOn7h/builds/t3DcEFmToQIj1Kx8V/openapi.json
