# TVCMall Wholesale Scraper (`crawlerbros/tvcmall-scraper`) Actor

Scrape TVCMall.com - a global B2B wholesale marketplace for mobile accessories, consumer electronics, and related categories. Search by keyword, browse by category, or fetch product details by URL, with pricing, bulk discount tiers, images, and stock status.

- **URL**: https://apify.com/crawlerbros/tvcmall-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/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

## TVCMall Wholesale Scraper

Scrape [TVCMall.com](https://www.tvc-mall.com) — a global B2B wholesale marketplace for mobile accessories, cell phone parts, consumer electronics, and related categories. Search by keyword, browse a full product category, or pull details for specific product URLs — with pricing, bulk quantity discount tiers, images, and ratings. No login, cookies, or API key required.

### What this actor does

- **Three modes:** `search` (keyword, optionally narrowed to a category), `byCategory` (20 top-level categories), `byProductUrls` (direct lookup)
- **Bulk pricing:** every record includes the full quantity-discount price ladder (buy more, pay less per unit)
- **Filters:** min/max price (USD, applied server-side), brand, part condition (OEM / OEM Disassembly / Assembly / Non-OEM but high quality / Other — mainly for replacement-parts categories), free-samples-only, merchandising tag (New Arrivals / Best Sellers / Bulk Buying / Recommended / EU Top Ranking / Clearance / Top Rated / In Stock Only / Customizable / Special Offers), dispatch lead time, sort by price / best-selling / discount / popularity (catalog-wide order in `byCategory` mode) or rating / newest / video-listings-first
- **Empty fields are omitted** — every record contains only real, populated data
- **De-duplicated** — products cross-listed under multiple subcategories are only ever emitted once per run

### Output per product

- `sku`, `thirdPartySku` — unique product identifiers
- `title`
- `productUrl` — canonical product page
- `imageUrl` — CDN-hosted product image
- `videoUrl` — YouTube product video (present only on the small subset of listings that have one)
- `price`, `priceFormatted`, `discountedPrice`, `discountedPriceFormatted`, `discountPercent`
- `bulkMinPrice`, `bulkMinQuantity` — best available unit price at highest quantity tier
- `minOrderQuantity` — the minimum quantity you must order (some SKUs can't be ordered below 2+ units even though the price ladder still shows a unit price at quantity 1)
- `priceTiers[]` — `{ minQuantity, unitPrice }` quantity-discount ladder
- `currencyCode`
- `categoryName`, `categoryUrl`
- `leadTime` — estimated dispatch time
- `reviewCount`, `rating` (only present when the product has reviews)
- `brand`
- `condition` — part-condition grade (OEM / OEM Disassembly / Assembly / Non-OEM But High Quality / Others), present mainly on replacement-parts listings
- `properties` — key specs (color, weight, dimensions, packaging, etc.)
- `availableColors`, `variantCount` — color options and total variant count (present when the product has more than one color/style variant)
- `publishedAt` — when the product listing was first published
- `lastUpdatedAt` — when the product listing (price/details) was last refreshed on TVCMall
- `freeSampleAvailable` — present (`true`) when TVCMall allows ordering a free sample of this product
- `shippingRestriction` — present when the product carries a special logistics tag (e.g. contains a battery, is fragile)
- `stockRemaining`, `stockTotal` (present when a limited-time quantity restriction is active, e.g. clearance/special-offer listings)
- `promotionEndsAt` (present when the product has an active limited-time clearance/discount campaign)
- `description` (detail lookups only)
- `customizable` — present when the product supports custom branding/packaging
- `sourceUrl`, `recordType: "product"`, `scrapedAt`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byCategory` / `byProductUrls` |
| `searchQuery` | string | `bluetooth earbuds` | Free-text keyword (mode=search) |
| `category` | string | – | One of 20 top-level categories — required to browse (mode=byCategory), optional as a narrowing filter on top of a keyword search (mode=search) |
| `productUrls` | array | – | Full product page URLs (mode=byProductUrls) |
| `minPrice` | number | – | Drop products cheaper than this (USD) |
| `maxPrice` | number | – | Drop products more expensive than this (USD) |
| `brand` | string | – | Only return products from this brand, e.g. `RhinoShield` (search/byCategory) |
| `condition` | string | – | `oem` / `oemDisassembly` / `assembly` / `nonOemHighQuality` / `other` — part-condition grade, mainly for replacement-parts categories (search/byCategory) |
| `sortBy` | string | `relevance` | `relevance` / `priceAsc` / `priceDesc` / `ratingDesc` / `bestSelling` / `discountDesc` / `popularity` / `newest` / `video` |
| `freeSamplesOnly` | boolean | `false` | Only return products eligible for a free sample order |
| `tag` | string | – | `newArrivals` / `bestSellers` / `bulkBuying` / `recommended` / `euTopRanking` / `clearance` / `goodReviews` (Top Rated) / `inStockOnly` / `customizable` / `specialOffers` (search/byCategory) |
| `leadTime` | string | – | Dispatch lead-time band: `0-1` / `1-3` / `4-7` / `7-10` / `11-30` / `31-50` days (search/byCategory) |
| `maxItems` | int | `30` | Hard cap (1–500) |

#### Example: keyword search with a price ceiling

```json
{
  "mode": "search",
  "searchQuery": "bluetooth earbuds",
  "maxPrice": 20,
  "maxItems": 50
}
```

#### Example: keyword search narrowed to a category

```json
{
  "mode": "search",
  "searchQuery": "case",
  "category": "apple",
  "sortBy": "priceAsc",
  "maxItems": 50
}
```

#### Example: browse a full category, cheapest first

```json
{
  "mode": "byCategory",
  "category": "cellPhoneCases",
  "sortBy": "priceAsc",
  "maxItems": 100
}
```

#### Example: look up specific products

```json
{
  "mode": "byProductUrls",
  "productUrls": [
    "https://www.tvc-mall.com/details/lens-filter-for-dji-mavic-mini-camera-len-multi-coated-filter-nd8-pl-sku682500024a.html"
  ]
}
```

### Use cases

- **Dropshipping / e-commerce sourcing** — find wholesale suppliers and bulk pricing for mobile accessories and electronics
- **Price monitoring** — track price and discount changes for specific SKUs over time
- **Category research** — see the full breadth of a product category with quantity-discount pricing
- **Sourcing agents** — bulk-export catalogs for client price comparisons

### FAQ

**What is TVCMall?**  A wholesale/dropship marketplace primarily for mobile phone accessories, cell phone cases, parts, consumer electronics, and related categories, selling in bulk with quantity-based unit-price discounts.

**Do I need a TVCMall account?**  No — this actor uses only the site's public guest browsing surface. No login, cookies, or API key are required.

**What currency are prices in?**  USD by default (see `currencyCode` on each record).

**What does `priceTiers` mean?**  TVCMall discounts the per-unit price as you buy more. `priceTiers` is the full ladder — e.g. `{minQuantity: 1, unitPrice: 9.90}`, `{minQuantity: 150, unitPrice: 9.17}` — so you can see the best price at any order size.

**Why do some products have no `rating`/`reviewCount`?**  Those fields are only included when the product actually has reviews; a fabricated `0` rating for an unreviewed product would be misleading, so it's omitted instead.

**What does `freeSampleAvailable` mean?**  TVCMall lets buyers order a free sample of certain products before committing to a bulk order. Set `freeSamplesOnly: true` to only return products with this option.

**What does `brand` filter on?**  TVCMall's own brand facet for the current search/category (e.g. `RhinoShield`, `Aulumu`, `Baseus`). Matching is case-insensitive, exact match preferred, with a substring fallback for close spellings. If no brand in the current search/category matches, the run returns 0 records with a status message rather than silently ignoring the filter. Applies to `search` and `byCategory` modes only.

**What does `condition` filter on?**  TVCMall's own condition grade for replacement-parts listings: `oem` (genuine OEM), `oemDisassembly` (OEM pulled from a working device), `assembly` (pre-assembled part), `nonOemHighQuality` (compatible aftermarket, high quality), and `other`. This is mainly meaningful on replacement-parts categories (screens, flex cables, batteries, charging ports, back covers, etc.) — categories without this attribute (e.g. LED lights, car chargers) will simply return 0 matches for a condition filter. Applies to `search` and `byCategory` modes only.

**What does `tag` filter on?**  TVCMall's own merchandising tags: `newArrivals` (recently listed), `bestSellers` (top-selling), `bulkBuying` (products with active bulk-order deals), `recommended` (TVCMall's staff-picked items), `euTopRanking` (top-ranking items for the EU market), `clearance` (clearance-priced stock), `goodReviews` (highly-rated items), `inStockOnly` (items with immediate stock availability), `customizable` (products that support custom branding/packaging), and `specialOffers` (products with a special-offer/stock-clearance discount, a distinct set from `clearance`). Applies to `search` and `byCategory` modes only. Note: `inStockOnly` combined with **both** `searchQuery` and `category` at once has no effect (TVCMall's keyword search already only ever returns in-stock listings, so the tag is redundant — not dropped — in that specific combination); it filters normally with `searchQuery` alone or `category` alone (`byCategory` mode).

**What does `leadTime` filter on?**  The estimated dispatch time band shown on the product page (e.g. `1-3` for "1 - 3 days"). Applies to `search` and `byCategory` modes only.

**Does `sortBy` sort the whole catalog, or just what was fetched?**  In `byCategory` mode, `priceAsc`/`priceDesc`/`bestSelling`/`discountDesc`/`popularity` reflect TVCMall's true catalog-wide server-side order. In `search` mode (keyword search, with or without a category filter), sorting is always applied client-side instead, over the collected keyword-matching batch — this is deliberate: TVCMall's server-side sort silently weakens or drops keyword relevance when combined with a keyword search, so client-side sorting guarantees results stay on-topic. `priceAsc`/`priceDesc`/`ratingDesc`/`discountDesc`/`newest`/`video` are fully supported client-side in `search` mode; `bestSelling`/`popularity` have no client-side equivalent there (no sales-count/popularity field to sort by) and fall back to relevance order.

**What categories are supported?**  Cell Phone Accessories, Cell Phone Cases, Cell Phone Parts, Smartwatch Accessories, Photo & Video, Computer & Networking, Consumer Electronics, Car Accessories, Home & Garden, Sports & Outdoors, and brand hubs for Apple, Samsung, Huawei, Xiaomi, Oppo, Motorola, Honor, Lenovo, OnePlus, and Other Brands (smaller brands not broken out individually).

**Can I combine keyword search with a category?**  Yes — set both `searchQuery` and `category` in `mode=search` to narrow keyword results to just that category (e.g. `searchQuery: "case"` + `category: "apple"` returns only Apple-related cases). Leave `category` unset to search the whole site.

**How fresh is the data?**  Real-time — every run queries TVCMall's live product search and detail APIs directly.

# Actor input Schema

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

What to fetch.

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

Free-text keyword search, e.g. `bluetooth earbuds`, `led light`, `phone case`.

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

Top-level product category. Required to browse (mode=byCategory); optional as a narrowing filter on top of a keyword search (mode=search).

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

Full TVCMall product detail page URLs (e.g. `https://www.tvc-mall.com/details/...-sku123456a.html`).

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

Drop products cheaper than this.

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

Drop products more expensive than this.

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

`priceAsc`/`priceDesc`/`bestSelling`/`discountDesc`/`popularity` use TVCMall's own server-side catalog order in `byCategory` mode. In `search` mode (keyword search, with or without a category filter) all sorting is applied client-side instead, over the collected keyword-matching batch, to guarantee results stay relevant to your search query — `priceAsc`/`priceDesc`/`ratingDesc`/`discountDesc`/`newest`/`video` are fully supported this way, while `bestSelling`/`popularity` fall back to relevance order in `search` mode (TVCMall exposes no sales-count/popularity field to sort by client-side).

## `freeSamplesOnly` (type: `boolean`):

Only return products TVCMall marks as eligible for a free sample order.

## `tag` (type: `string`):

Only return products carrying this TVCMall merchandising tag.

## `brand` (type: `string`):

Only return products from this brand, e.g. `RhinoShield`, `Aulumu`, `Baseus`. Matched against TVCMall's brand facet for the current search/category (case-insensitive, exact match preferred, falls back to a substring match). Applies to `search` and `byCategory` modes only.

## `condition` (type: `string`):

Only return products of this condition grade. Mainly relevant for replacement-parts categories (screens, flex cables, batteries, charging ports, back covers, etc.) — other categories will simply return 0 matches for a condition filter. Applies to `search` and `byCategory` modes only.

## `leadTime` (type: `string`):

Only return products whose estimated dispatch time matches this band.

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "searchQuery": "bluetooth earbuds",
  "productUrls": [],
  "sortBy": "relevance",
  "freeSamplesOnly": false,
  "tag": "",
  "condition": "",
  "leadTime": "",
  "maxItems": 30
}
```

# Actor output Schema

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

Dataset containing all scraped TVCMall 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": "bluetooth earbuds",
    "productUrls": [],
    "sortBy": "relevance",
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/tvcmall-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": "bluetooth earbuds",
    "productUrls": [],
    "sortBy": "relevance",
    "maxItems": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/tvcmall-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": "bluetooth earbuds",
  "productUrls": [],
  "sortBy": "relevance",
  "maxItems": 30
}' |
apify call crawlerbros/tvcmall-scraper --silent --output-dataset

```

## MCP server setup

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