# ROMWE Scraper (`crawlerbros/romwe-scraper`) Actor

Scrape ROMWE (us.romwe.com) product listings - search by keyword or fetch full product detail by URL. Prices, images, ratings, attributes. No login required.

- **URL**: https://apify.com/crawlerbros/romwe-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **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/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

## ROMWE Scraper

Scrape [ROMWE](https://us.romwe.com) — the global fast-fashion dropship marketplace. Search products by keyword, browse a catalog category, or fetch full product detail by URL: prices, discounts, ratings, images, and attributes. No login, no cookies, no residential proxy required.

### What this actor does

- **Three modes:** `search` (keyword search with sort + price/rating filters), `byCategory` (browse a curated or custom catalog category), and `byUrl` (fetch specific product pages directly)
- **Full pricing:** retail price, sale price, discount percentage, currency symbol
- **Ratings:** review count and average rating (when available)
- **Media:** main image plus full image gallery
- **Attributes:** color, size, pattern, and other product-specific attributes
- **Empty fields are omitted** — every record only contains fields that were actually extracted

### Modes

#### Search (`mode: "search"`)

Search ROMWE's catalog by free-text keyword (`searchQuery`), e.g. `"phone case"`, `"summer dress"`, `"sneakers"`. Supports sorting (`sortBy`) and price/rating filters. Price (`salePrice`/`retailPrice`/`discountPercent`) is always populated straight from the listing page. When `enrichWithPrice` is on (default), each result is additionally enriched with a full detail-page fetch so rating/full-resolution images/attributes are populated too; turn it off for a faster, lighter-weight run that still includes price but skips the extra fetch.

#### By Category (`mode: "byCategory"`)

Browse a ROMWE catalog category and page through it like a shopper would. Pick from 33 curated categories (`categoryUrl`, e.g. Women Clothing, Men Denim, Shoes, Jewelry & Watches) or supply any ROMWE `.../<name>-c-<id>.html` category URL via `categoryUrls`. Supports the same `sortBy` and price/rating filters as `search`.

#### By URL (`mode: "byUrl"`)

Fetch one or more specific product pages directly by URL (`productUrls`) — useful when you already have product links and want full detail without searching.

### Output fields

| Field | Description |
|---|---|
| `productId` | Numeric ROMWE goods ID |
| `title` | Product title |
| `sku` | ROMWE SKU / goods\_sn |
| `sourceUrl` | Canonical product page URL (emitted as `productUrl` instead when `mode=search`/`byCategory` and `enrichWithPrice` is turned off, since no detail-page fetch happens in that fast path) |
| `retailPrice` | List price (USD) |
| `salePrice` | Current sale price (USD) |
| `discountPercent` | Discount off retail price |
| `currencySymbol` | Currency symbol (e.g. `$`) |
| `reviewCount` | Number of reviews (when > 0) |
| `rating` | Average rating 0-5 (when reviews exist) |
| `brand` | Brand name (when set) |
| `rewardPoints` | ROMWE loyalty points earned on purchase (mode=byUrl, or search/byCategory with `enrichWithPrice`) |
| `description` | Short SEO description |
| `imageUrl` | Primary product image |
| `imageUrls[]` | Full image gallery |
| `attributes[]` | `{name, value}` pairs (color, size, pattern, ...) |
| `availableColors[]` | Other color variants of this product — `{color, productId, productUrl, isCurrent}` |
| `availableSizes[]` | Size/fit variants this product is sold in (e.g. phone-case models, clothing sizes) — `{size, inStock}` (mode=byUrl, or search/byCategory with `enrichWithPrice`) |
| `sizeChart[]` | Body-measurement size chart published by ROMWE for apparel — `{size, measurements: {bust, waistSize, hipSize, length, ...}, part}` (`part` only present on multi-part sets, e.g. a top+pants set with separate charts per piece; measurement keys vary by garment type). Naturally omitted for non-apparel items (mode=byUrl, or search/byCategory with `enrichWithPrice`) |
| `category` | Category name (top-level ancestor) |
| `categoryId` | Category ID (of the product's own leaf category) |
| `categoryPath[]` | Full category breadcrumb from root to the product's own leaf category, e.g. `["Women Apparel", "Women Plus Clothing", "Plus Size Dresses"]` (mode=byUrl, or search/byCategory with `enrichWithPrice`) |
| `inStock` | Boolean stock status |
| `isOnSale` | Boolean sale flag |
| `freeReturnEligible` | Boolean — whether ROMWE marks the product as eligible for free returns (mode=byUrl, or search/byCategory with `enrichWithPrice`) |
| `recordType` | Always `"product"` |
| `scrapedAt` | UTC ISO timestamp |

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byCategory` / `byUrl` |
| `searchQuery` | string | `phone case` | Free-text keyword (mode=search) |
| `categoryUrl` | select | – | Curated category (mode=byCategory) |
| `categoryUrls` | array | – | Custom ROMWE category URLs (mode=byCategory) |
| `productUrls` | array | – | Full ROMWE product page URLs (mode=byUrl) |
| `sortBy` | string | `recommend` | `recommend` / `priceAsc` / `priceDesc` / `newIn` (mode=search/byCategory) |
| `minPrice` / `maxPrice` | number | – | Sale-price range (USD) |
| `minRating` | number | – | Minimum average rating 0-5 (products with no reviews yet always pass) |
| `inStockOnly` | boolean | `false` | Only emit products currently in stock (works with or without `enrichWithPrice`; always available for byUrl) |
| `onSaleOnly` | boolean | `false` | Only emit products currently discounted |
| `freeReturnOnly` | boolean | `false` | Only emit products eligible for free returns (requires `enrichWithPrice` for search/byCategory; always available for byUrl) |
| `enrichWithPrice` | boolean | `true` | Fetch full product detail (rating/full-res images/attributes) for each search/byCategory result (mode=search/byCategory) |
| `maxItems` | int | `24` | Hard cap on emitted records (1-500) |
| `proxyConfiguration` | object | Apify Proxy (auto) | Used only after detail-page fetches hit 3+ consecutive soft-404s; leave default unless runs are consistently affected |

#### Example: keyword search with enrichment

```json
{
  "mode": "search",
  "searchQuery": "summer dress",
  "sortBy": "priceAsc",
  "minPrice": 10,
  "maxPrice": 40,
  "maxItems": 30
}
```

#### Example: fast lightweight search (no detail-page fetch)

```json
{
  "mode": "search",
  "searchQuery": "sneakers",
  "enrichWithPrice": false,
  "maxItems": 50
}
```

#### Example: browse a curated category

```json
{
  "mode": "byCategory",
  "categoryUrl": "https://us.romwe.com/Shoes-c-2586.html",
  "sortBy": "newIn",
  "inStockOnly": true,
  "maxItems": 40
}
```

#### Example: fetch specific products by URL

```json
{
  "mode": "byUrl",
  "productUrls": [
    "https://us.romwe.com/Some-Product-Name-p-2979580.html"
  ]
}
```

### Use cases

- **Dropship & fast-fashion resellers** — track ROMWE catalog pricing and stock for sourcing decisions
- **Price monitoring** — watch sale/discount fluctuations on specific products or categories
- **Trend research** — scan "newIn" listings across categories for emerging styles
- **Market research** — compare attributes, ratings, and pricing across competitor fast-fashion catalogs
- **Catalog aggregation** — bulk-export product data for a comparison shopping site

### Limitations

- Reviews/ratings are only present on records where ROMWE has published at least one review; new listings are shipped without `reviewCount`/`rating` rather than a `0` sentinel.
- Regional pricing (non-US storefronts) is out of scope for v1 — all prices are USD via `us.romwe.com`.
- `freeReturnOnly` can only be determined from a per-product detail-page fetch (unlike price/stock, which the search/category listing already carries), so the actor walks a deeper candidate queue and gives up later than for price-only filters when few matches are found. If ROMWE's edge network is intermittently rejecting detail-page fetches (occasional soft-404s from datacenter IP ranges — automatically retried and, after a sustained burst, escalated to Apify Proxy), a run with `freeReturnOnly` (or `enrichWithPrice` on) may return fewer records than really exist; re-running usually recovers full coverage.

### FAQ

**Do I need a proxy or login?** No — every request runs directly against ROMWE's public, unauthenticated pages. Apify Proxy (datacenter, `AUTO`) is only engaged automatically after a burst of soft-404s on detail-page fetches, as a fallback.

**How is pricing extracted?** ROMWE server-renders a JSON blob (`gbRawData`) into every page it sends, including full pricing/rating/image data on product-detail pages. The actor parses this blob directly — no private API calls.

**Why is `search` mode slower than `byUrl`?** With `enrichWithPrice` on, each search result triggers one additional detail-page fetch to populate rating/full-resolution images/attributes (price is already included without it). Turn `enrichWithPrice` off for a fast title/price/image/URL-only pass.

**Is this affiliated with ROMWE?** No — this is a third-party actor that reads ROMWE's public storefront pages; it is not built or endorsed by ROMWE/SHEIN Group.

**Why are `reviewCount`/`rating` missing on some products?** ROMWE only shows those fields once a product has at least one published review; new or low-traffic listings simply omit them rather than showing a `0`.

**Can I get every product in a category?** Yes — leave `maxItems` high (or raise it up to 500) and the actor pages through the category listing until it runs out of products or hits your cap.

**Are prices region-specific?** No — this actor scrapes `us.romwe.com` only, so all prices are in USD.

**Why did my `freeReturnOnly` run return fewer results than expected?** Free-return eligibility can only be read from a product's detail page, so `freeReturnOnly` requires `enrichWithPrice` (or `mode=byUrl`) and walks a deeper candidate queue than price-only filters. If ROMWE's edge network is intermittently rejecting detail-page fetches, re-run — coverage usually recovers.

**How current is the data?** Every run fetches ROMWE's live pages at request time — there is no caching, so prices/stock reflect what's on the site right now.

# Actor input Schema

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

What to fetch.

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

Free-text keyword search, e.g. `phone case`, `summer dress`, `sneakers`.

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

Result ordering.

## `categoryUrl` (type: `string`):

Pick a popular ROMWE catalog category. Leave as "Custom URL(s) below" and use `categoryUrls` to browse any other category.

## `categoryUrls` (type: `array`):

Any ROMWE `.../<name>-c-<id>.html` category page URLs. Combined with `categoryUrl` if both are set.

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

Full ROMWE product page URLs, e.g. `https://us.romwe.com/Some-Product-Name-p-2979580.html`.

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

Drop products cheaper than this (sale price, USD).

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

Drop products more expensive than this (sale price, USD).

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

Drop products with a review rating below this (0-5). Products with no reviews yet are always kept.

## `inStockOnly` (type: `boolean`):

Only emit products currently in stock. Stock status is available on both the search/category listing page and the product detail page, so this works whether or not `enrichWithPrice` is on.

## `onSaleOnly` (type: `boolean`):

Only emit products currently marked on sale (discounted below their retail price).

## `freeReturnOnly` (type: `boolean`):

Only emit products ROMWE marks as eligible for free returns. Free-return eligibility only appears on the product detail page, so this has no effect unless `enrichWithPrice` is also on (mode=search/byCategory), or is used with mode=byUrl.

## `enrichWithPrice` (type: `boolean`):

When on, each search/category result is enriched with a detail-page fetch to include rating, full-resolution images, and attributes (price is already included either way, from the listing page). When off, only listing-page fields (title, price, image, URL) are emitted and the run is much faster.

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

Hard cap on emitted records.

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

ROMWE's product detail pages occasionally soft-block a datacenter IP with a burst of spurious 404s. The actor connects directly first and only engages this proxy after 3+ consecutive 404s on detail pages -- leave the default (Apify Proxy, automatic) unless your runs are consistently affected.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "phone case",
  "sortBy": "recommend",
  "categoryUrl": "",
  "categoryUrls": [],
  "productUrls": [],
  "inStockOnly": false,
  "onSaleOnly": false,
  "freeReturnOnly": false,
  "enrichWithPrice": true,
  "maxItems": 24,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Dataset containing all scraped ROMWE products.

# 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": "phone case",
    "sortBy": "recommend",
    "categoryUrl": "",
    "categoryUrls": [],
    "productUrls": [],
    "inStockOnly": false,
    "onSaleOnly": false,
    "freeReturnOnly": false,
    "enrichWithPrice": true,
    "maxItems": 24,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/romwe-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": "phone case",
    "sortBy": "recommend",
    "categoryUrl": "",
    "categoryUrls": [],
    "productUrls": [],
    "inStockOnly": False,
    "onSaleOnly": False,
    "freeReturnOnly": False,
    "enrichWithPrice": True,
    "maxItems": 24,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/romwe-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": "phone case",
  "sortBy": "recommend",
  "categoryUrl": "",
  "categoryUrls": [],
  "productUrls": [],
  "inStockOnly": false,
  "onSaleOnly": false,
  "freeReturnOnly": false,
  "enrichWithPrice": true,
  "maxItems": 24,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call crawlerbros/romwe-scraper --silent --output-dataset

```

## MCP server setup

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