# DHgate Scraper (`crawlerbros/dhgate-scraper`) Actor

Scrape DHgate - China's wholesale & B2C marketplace. Search products, browse categories and seller shops, or fetch product pages with full details: prices, MOQ, seller ratings, sales counts, specs, images, variants and shipping info.

- **URL**: https://apify.com/crawlerbros/dhgate-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** E-commerce, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## DHgate Scraper

Scrape **DHgate** — one of the world's largest wholesale marketplaces with 30+ million products from Chinese and global suppliers. Search products by keyword, browse the 21 top-level categories, walk a seller shop's entire catalog, or fetch individual product pages with full detail: price tiers, stock countries, shipping costs, seller reputation and more. No login required.

### What this actor does

- **Four modes:** `search` (keyword), `browseByCategory` (21 top-level categories), `shopProducts` (full seller catalog by shop ID), `byUrl` (product / category / store URLs)
- **Full product detail:** price min/max and range, wholesale price tiers, variants (color/size with images), stock countries, shipping cost & delivery estimate, free-shipping flag, money-back days
- **Seller intelligence:** seller name, store URL, rating (0–5), positive-feedback percentage, seller level/tier, year established, company introduction
- **Commerce signals:** sold count, min order qty, measure unit, dimensions, gross weight, description with bullets and specs
- **Filters:** price range (USD), min seller rating, keyword on title, shipping country
- **Anti-bot:** browser-impersonated TLS (curl\_cffi) with backoff retries, automatic Playwright escalation on repeated WAF blocks, and an optional lazy proxy (free Apify AUTO group) for blocked regions
- **Empty fields are omitted**

### Output per product

- `id` (item code), `productId`, `skuId`, `seoName`, `supplierId`
- `title`, `categoryName`, `description`, `descriptionBullets[]`, `specifications[]` (name/value pairs)
- `priceMin`, `priceMax`, `priceRange`, `priceTiers[]` (`startQty`/`endQty`/`price`), `minOrderQty`, `measureUnit`
- `variants[]` — `attribute`, `name`, `imageUrl`
- `images[]` — gallery image URLs, `imageUrl` (listings)
- `stockCountries[]`, `stockCountry`, `shipToCountry`, `shipToCountryCode`
- `shippingCostUsd`, `shippingCurrency`, `shippingDays[]`, `freeShipping`, `moneyBackDays`, `deliveryEstimate`
- `saleNum` / `soldCount`, `dimensionsCm`, `grossWeightKg`, `lastModifiedDate`
- `rating`, `reviewCount`, `transactionCount`, `reviewBreakdown` (per-star counts)
- `sellerName`, `sellerStoreUrl`, `sellerRatingPercent`, `sellerLevel`, `sellerTier`, `yearEstablished`, `companyIntroduction`
- `sourceUrl`, `productUrl`, `recordType: "product"`, `scrapedAt`

### Output per shop

- `storeName`, `storeUrl`, `logoUrl`, `positiveFeedbackPercent`, `transactionCount`, `onTimeDeliveryRate`, `sellerLevel`, `sellerTier`
- `sourceUrl`, `recordType: "shop"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `browseByCategory` / `shopProducts` / `byUrl` |
| `searchQuery` | string | `smart watch` | Free-text keyword (mode=search) |
| `category` | string | `electronics` | One of 21 top-level categories (mode=browseByCategory) |
| `startUrls` | array | – | Product / category / store URLs (mode=byUrl) |
| `shopId` | int | – | Seller shop ID, e.g. `22268785` (mode=shopProducts) |
| `minPrice` / `maxPrice` | number | – | Price range filter in USD |
| `minRating` | number | – | Min seller rating (0–5) |
| `containsKeyword` | string | – | Keep only products whose title contains this text |
| `country` | string | – | Keep only products shippable to this country (25 options) |
| `maxItems` | int | `50` | Hard cap (1–1000) |
| `proxyConfiguration` | object | off | Optional proxy, used lazily only when DHgate's WAF blocks direct access |

#### Example: search products

```json
{
  "mode": "search",
  "searchQuery": "smart watch",
  "maxItems": 50
}
```

#### Example: browse a category with filters

```json
{
  "mode": "browseByCategory",
  "category": "jewelry",
  "minPrice": 20,
  "maxPrice": 100,
  "minRating": 4.5,
  "maxItems": 100
}
```

#### Example: a seller's whole catalog

```json
{
  "mode": "shopProducts",
  "shopId": 22268785,
  "maxItems": 200
}
```

#### Example: fetch specific products

```json
{
  "mode": "byUrl",
  "startUrls": [
    "https://www.dhgate.com/product/10a-premium-original-luxury-handbags-designer/1086662889.html"
  ]
}
```

### Data Source

DHgate's public storefront pages (`dhgate.com/wholesale/…`, `/product/…`, `/store/…`) — the same SSR pages any shopper sees. Product detail records are built from the page's embedded React server-component (RSC) stream, which mirrors the live product data the website renders. This actor is a third-party tool and is not affiliated with, endorsed by, or sponsored by DHgate.

### Limitations

- **Fuzzy search fallback:** like the website itself, a search that matches nothing returns DHgate's "popular products" fallback listing instead of an empty page. Records are always real products with working source URLs.
- **Captcha / WAF blocks:** DHgate's Akamai WAF intermittently challenges datacenter IPs. The actor retries with backoff, escalates to a real browser automatically, and honors an optional proxy configuration for persistently blocked regions. Some runs may still fail during an active block — rerun later or enable the proxy.
- **Ship-to country:** the `country` filter is best-effort — shipping availability is read per-product from the ship-to country the page was rendered for.
- **Unicode queries:** DHgate's search handles non-Latin keywords, but result titles may fall back to transliterated or popular-product suggestions.
- **curl HEAD checks on source URLs return 403** from a plain HTTP client — the pages are served to real browsers and to this actor's impersonated client.

### Use cases

- **Wholesale sourcing** — find suppliers, price tiers and minimum order quantities for resale
- **Competitor price monitoring** — track price ranges and discounts per category
- **Supplier due diligence** — seller ratings, feedback percentages and store history
- **Product research** — variants, specs, shipping times and stock countries for market analysis
- **Marketplace analytics** — sold counts and review distributions as demand signals

### FAQ

**Is a DHgate account required?** No. All data comes from public storefront pages.

**Does the actor buy anything or place orders?** No — it only reads public pages.

**What is `priceTiers`?** DHgate's wholesale pricing: the unit price per quantity band (e.g. 1–3 pieces at $300, 4+ pieces at $286.02).

**What does the `country` filter do?** It keeps products the page reports as shippable to the chosen country and passes the country to DHgate's search so shipping quotes are rendered for that market.

**How do I find a shop ID?** Shop IDs are in store URLs: `dhgate.com/store/22268785` → `22268785`. Product pages also carry `sellerStoreUrl`.

**Why do product pages sometimes take longer?** Each product page is fetched with the impersonated client and retried on blocks; the page HTML is large (RSC payload), which is also why detail records are rich.

**How fresh is the data?** Live — every run reads the current storefront pages at run time.

# Actor input Schema

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

What to fetch from DHgate.

## `searchQuery` (type: `string`):

Free-text keyword (mode=search).

## `category` (type: `string`):

DHgate category to browse.

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

Product, category, store or search URLs, e.g. `https://www.dhgate.com/product/designer-bag/1086662889.html`.

## `shopId` (type: `integer`):

DHgate supplier shop ID, e.g. `22268785`. Found in store URLs: dhgate.com/store/22268785.

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

Drop products whose lowest price is below this.

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

Drop products whose lowest price is above this.

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

Drop products whose seller rating is below this (0–5).

## `containsKeyword` (type: `string`):

Only emit products whose title contains this keyword (case-insensitive).

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

Only emit products shippable to this country (best-effort; shipping info is per-product).

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

Hard cap on emitted records.

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

Optional. Used only when DHgate's WAF blocks direct access (lazy trigger) — the free AUTO group is enough for most regions.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "smart watch",
  "category": "electronics",
  "startUrls": [
    "https://www.dhgate.com/product/10a-premium-original-luxury-handbags-designer/1086662889.html"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Dataset containing all scraped DHgate product records.

# 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 = {
    "mode": "search",
    "searchQuery": "smart watch",
    "category": "electronics",
    "startUrls": [
        "https://www.dhgate.com/product/10a-premium-original-luxury-handbags-designer/1086662889.html"
    ],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/dhgate-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 = {
    "mode": "search",
    "searchQuery": "smart watch",
    "category": "electronics",
    "startUrls": ["https://www.dhgate.com/product/10a-premium-original-luxury-handbags-designer/1086662889.html"],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/dhgate-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 '{
  "mode": "search",
  "searchQuery": "smart watch",
  "category": "electronics",
  "startUrls": [
    "https://www.dhgate.com/product/10a-premium-original-luxury-handbags-designer/1086662889.html"
  ],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call crawlerbros/dhgate-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/dhgate-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/LXm3JuIB2YRhBzEss/builds/15Oc1RnIBWN3YXHvo/openapi.json
