# Chotot.com Scraper: Chợ Tốt Vietnam (search, filters, alerts) (`datahamster/chotot-vn-listings`) Actor

Chotot.com scraper for Chợ Tốt (Cho Tot), Vietnam's largest classifieds: search by keyword, category, region and price. Flat rows with VND price, category, city, district, ward, coordinates, seller type, photos and attributes (brand, model, mileage). Monitor mode alerts on new ads and price cuts.

- **URL**: https://apify.com/datahamster/chotot-vn-listings.md
- **Developed by:** [Viktor Dubnytskiy](https://apify.com/datahamster) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 result items

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?

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

## Chotot.com Scraper: Chợ Tốt Vietnam (search, filters, alerts)

A Chotot.com scraper for **Chợ Tốt** (Cho Tot), Vietnam's largest classifieds marketplace: search by keyword, category, region and price and get every listing as one flat row with VND price, ward-level location and the category attributes Chợ Tốt returns. Monitor mode on a saved Task gives you only the listings that are new or changed price since your last run.

### What you get — example output

One row per listing. Real values from the example dataset (query `iphone 15`):

| Field | Example value | What it is |
|---|---|---|
| `id` | `chotot-134505021` | Stable row key (`chotot-` + listing id) |
| `title` | `Apple iPhone 15 128GB Xanh` | Listing headline |
| `price` / `priceLabel` | `15950000` / `15.950.000 đ` | Price as a number in VND, plus the label Chợ Tốt prints |
| `categoryName` | `Điện thoại` | Category name (`categoryId` `5010`) |
| `city` / `district` / `ward` | `Tp Hồ Chí Minh` / `Huyện Hóc Môn` / `Xã Bà Điểm` | Three levels of Vietnamese location |
| `lat` / `lon` | `10.841164` / `106.59671` | Listing coordinates |
| `sellerType` | `business` | `private` or `business` (`isShopVerified` flags verified shops) |
| `createdAt` | `2026-09-04T05:18:56+00:00` | When the listing was posted, in UTC |
| `params` | `{"mobile_brand": "1", "mobile_capacity": "6", "type": "s"}` | Category attributes as Chợ Tốt returns them |

Full field list: `id`, `url`, `platform`, `country`, `title`, `description`, `price`, `currency`, `priceLabel`, `priceType`, `categoryId`, `categoryName`, `categoryPath`, `condition`, `city`, `district`, `ward`, `region`, `lat`, `lon`, `images[]`, `sellerId`, `sellerName`, `sellerType`, `isShopVerified`, `isSticky`, `createdAt`, `adType`, `params{}`, `query`, `rank`, `source`, `scrapedAt`.

### Use cases

- **Price research in Vietnam**: pull a whole category with VND prices and attributes to see the real market level for phones, bikes or flats.
- **Vehicle and property watching**: filter by category and region and get alerted when a matching listing appears or drops price.
- **Reselling and sourcing**: track a keyword in one city and catch underpriced listings the day they go up.

### How it works

The actor calls Chợ Tốt's own public listing API, so rows arrive structured — coordinates, ward, category attributes — without HTML parsing, and without a login, cookies or a proxy. Each query is paginated 50 listings per page until `maxPages` or `maxItems`. In `monitor` mode the current result set is compared with the state stored by the previous run of the same Task, and only new or re-priced listings are pushed, optionally summarised to a webhook or Telegram chat.

### Input

| Field | Meaning | Default |
|---|---|---|
| `queries` | Keywords in Vietnamese or English, e.g. `["iphone"]` | `["iphone"]` |
| `categoryId` | Chợ Tốt category id, e.g. `1000` real estate, `2010` cars, `5010` phones | — |
| `regionId` | Chợ Tốt `region_v2` id, e.g. `13000` Tp Hồ Chí Minh, `12000` Hà Nội | — |
| `priceFrom` / `priceTo` | Price range in VND, e.g. `5000000` / `20000000` | — |
| `adType` | `s` for sale, `k` wanted, `all` | `s` |
| `sortBy` | `newest`, `relevance`, `price_asc`, `price_desc` | `newest` |
| `maxPages` | Pages per query, 50 listings each | `4` |
| `maxItems` | Stop after this many listings | `20` |
| `mode` | `scrape`, or `monitor` for new/changed only | `scrape` |
| `webhookUrl`, `telegramBotToken`, `telegramChatId` | Where monitor-mode change summaries are sent | — |

### Pricing

| Event | Price |
|---|---|
| result | $0.001 per listing ($1 per 1,000) |
| monitor-check | $0.005 per monitor run |
| change | $0.001 per new/changed listing |

Charged only for listings actually pushed — an empty run costs you nothing. No proxy needed.

### Why this actor

- Ward-level location plus coordinates on every row, not just the city.
- Prices come back as numbers in VND alongside the Vietnamese label, so they are ready for maths.
- Category attributes (`params`) survive, which is what makes phone, motorbike and property rows comparable.
- Monitor mode with new-listing and price-drop alerts, delivered by webhook or Telegram.
- No Chợ Tốt account, no cookies and no proxy configuration.

### Limits

- Phone numbers are not included (Chợ Tốt reveals them only in-app).
- Search is capped by Chợ Tốt at 10,000 results per query; narrow by category or region.
- `params` keys and values are Chợ Tốt's own codes, not display labels.

### FAQ

**Can I monitor new listings for a search?** Yes. Save the input as a Task, set `mode: monitor` and schedule it — each run returns only listings that appeared or changed price since the previous run, and can POST a summary to `webhookUrl` or a Telegram chat.

**Can I scrape only Ho Chi Minh City or Hanoi?** Yes — set `regionId` to `13000` (Tp Hồ Chí Minh) or `12000` (Hà Nội); every row also carries `city`, `district` and `ward` for finer filtering downstream.

**Do I need a Chợ Tốt account or a proxy?** No. The actor reads the site's public listing API, so there is nothing to configure.

### Changelog

- 0.1: initial release.

***

If this actor saved you time, please leave a review on its Store page — it is the main way other buyers find it. Bug reports and field requests are welcome in the **Issues** tab.

# Actor input Schema

## `queries` (type: `array`):

Keywords to search, Vietnamese or English, one string per phrase, each paginated separately. Example: \["iphone", "xe may"]. Leave empty only if you pass categoryId.

## `categoryId` (type: `integer`):

Chợ Tốt category id (the cg parameter on chotot.com). Examples: 1000 real estate, 2000 vehicles, 2010 cars, 2020 motorbikes, 5000 electronics, 5010 phones, 8000 jobs. Optional.

## `regionId` (type: `integer`):

Chợ Tốt region\_v2 id. Examples: 13000 (Tp Ho Chi Minh), 12000 (Ha Noi), 3000 (Da Nang). Optional.

## `priceFrom` (type: `integer`):

Minimum price in Vietnamese dong (VND), whole number. Example: 5000000 for 5 million VND. Optional.

## `priceTo` (type: `integer`):

Maximum price in Vietnamese dong (VND), whole number. Example: 20000000. Optional.

## `adType` (type: `string`):

Listing type: s = for sale (can ban), k = wanted (can mua), all = both. Example: "s".

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

Result order: newest (newest first), relevance, price\_asc (cheapest first), price\_desc. Example: "newest".

## `maxPages` (type: `integer`):

How many result pages to fetch per query, 50 listings per page. Example: 4.

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

Stop the run after this many listings; you are charged only for listings actually pushed. Example: 20.

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

scrape = return all matching listings; monitor = return only listings that are new or changed price since the previous run of this saved Task. Example: "scrape".

## `monitorKey` (type: `string`):

Optional state key for monitor mode when the actor is started directly instead of from a saved Task; any stable string, e.g. "iphone-hcm".

## `webhookUrl` (type: `string`):

Optional HTTPS URL that receives a POST with the monitor-mode change summary (JSON). Example: "https://hooks.example.com/chotot".

## `telegramBotToken` (type: `string`):

Optional Telegram bot token used to send monitor-mode change summaries. Format: "123456789:AA...".

## `telegramChatId` (type: `string`):

Optional Telegram chat id that receives monitor-mode summaries. Example: "-1001234567890".

## Actor input object example

```json
{
  "queries": [
    "iphone"
  ],
  "adType": "s",
  "sortBy": "newest",
  "maxPages": 4,
  "maxItems": 20,
  "mode": "scrape"
}
```

# Actor output Schema

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

All pushed rows (dataset, JSON)

## `resultsTable` (type: `string`):

Dataset in the Console viewer

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

RUN\_SUMMARY record (pushed, skipped, emptyReason)

# 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 = {
    "queries": [
        "iphone"
    ],
    "adType": "s",
    "maxItems": 20,
    "mode": "scrape"
};

// Run the Actor and wait for it to finish
const run = await client.actor("datahamster/chotot-vn-listings").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 = {
    "queries": ["iphone"],
    "adType": "s",
    "maxItems": 20,
    "mode": "scrape",
}

# Run the Actor and wait for it to finish
run = client.actor("datahamster/chotot-vn-listings").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 '{
  "queries": [
    "iphone"
  ],
  "adType": "s",
  "maxItems": 20,
  "mode": "scrape"
}' |
apify call datahamster/chotot-vn-listings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datahamster/chotot-vn-listings"
        }
    }
}
```

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/YYhbjju6uKPMo15X6/builds/u1FoxMsXrOuYpjtAJ/openapi.json
