# Bobaedream Used Cars Scraper (Korea, new listing & price alert) (`superslowsloth/bobaedream-used-cars`) Actor

Scrape Bobaedream (보배드림) cyber-store, Korea's dealer used-car listings, domestic and imported: price in won, mileage, year, fuel, dealer and region per car, newest first, labelled new, price_drop, price_rise or unchanged since your last run.

- **URL**: https://apify.com/superslowsloth/bobaedream-used-cars.md
- **Developed by:** [Superslow Sloth](https://apify.com/superslowsloth) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.40 / 1,000 car listing scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Bobaedream Used Cars Scraper (Korean used cars, new listing & price alert)

Scrape the [Bobaedream](https://www.bobaedream.co.kr/cyber/CyberCar.php) (보배드림) cyber-store -
the dealer used-car showroom of one of Korea's biggest car communities, about
420 domestic and 1,900 imported cars for sale at any time - and get one flat
row per car: the asking price in **won** (Bobaedream prints 만원; the actor
converts), first registration year, mileage, fuel, horsepower and drivetrain,
the region, the dealer, how many views the listing has, and the date it was
listed.

Built as a **new-listing and price feed** for exporters, dealers and buyers of
Korean used cars: schedule the same search every morning, newest first, and
each row tells you whether the car is **new** since the last run, had a
**price drop** or a **price rise**, or is **unchanged**. Turn on *Only
changes* and you get - and pay for - just the new cars and the price moves.

### What the store holds (measured 2026-10-27)

| | domestic (국산차) | imported (수입차) | both |
|---|---|---|---|
| rows in the date-ordered list | 7,551 (108 pages) | 20,843 (298 pages) | 28,394 (406 pages) |
| of which for sale | 424 | 1,878 | 2,302 |
| new listings a day | about 3 | about 9 | about 12 |

The store keeps every listing it ever held, dated back to 2021. Most rows of
the default list are **history** - sold (팔림), expired (만료) or under
contract (계약) - with no price. The actor drops sold and expired rows by
default and stops reading once three pages in a row hold nothing for sale
(the last for-sale car was on page 15 of 108 domestic, page 49 of 298
imported). Every sort except newest lists **only** the cars for sale, which
makes it the cheapest way to take the whole current inventory: 7 pages
domestic, 27 imported.

### Input

| field | meaning |
|---|---|
| `market` | `domestic` (국산차, default), `imported` (수입차) or `all` (both together) |
| `makers` | Optional. Makers, one per line, English or Korean: `Hyundai`, `Kia`, `Genesis`, `Toyota`, `Mercedes-Benz`, `벤츠`... Each maker is its own search sharing the `maxItems` budget. Names not in Bobaedream's maker list for the market are skipped and logged |
| `fuels` | Optional. `gasoline`, `diesel`, `lpg`, `gasoline_lpg`, `gasoline_cng`, `gasoline_hybrid`, `lpg_hybrid`, `diesel_hybrid`, `cng`, `electric`, `hydrogen`, `other`. Several are OR-ed |
| `yearMin`, `yearMax` | Optional car-year range (연식), as Bobaedream's own year filter counts it |
| `priceMin`, `priceMax` | Optional price range **in 만원** (3000 = 30,000,000 won). The site's price filter drops every listing with no price on file, including most imported cars listed as 상담 (ask the dealer): 0 to 999,999 keeps 5,691 of 20,843 imported rows |
| `mileageMin`, `mileageMax` | Optional odometer range in km |
| `searchUrls` | Optional. `/cyber/CyberCar.php` list URLs copied from your browser after you set filters on the site - model, grade, region, colour, options, body type. Every parameter is kept; `page=3` starts on page 3. Single-car pages and other sites are skipped and logged |
| `sort` | `newest` (default, 최근 등록순), `price_asc`, `price_desc`, `year_newest`, `year_oldest`, `mileage_asc`, `mileage_desc`. Everything but `newest` lists only cars for sale |
| `maxItems` | Stop after reading this many listings in total, shared by every search, in order. Bobaedream shows 70 per page. For a feed this is the window watched: "the newest 100" |
| `registeredSince` | Optional `YYYY-MM-DD` (Korean time). Skip listings registered before it; with the newest sort the run stops at the first older one, so a daily feed reads only the pages it needs |
| `includeSold` | Off by default: sold and expired listings are dropped, not charged and not remembered |
| `changesOnly` | Output only listings that are new or whose price moved since the previous run of the same search. Off by default |
| `proxyConfiguration` | Apify datacenter proxy by default - see **Proxy** |

Paging walks `?page=1`, `?page=2`, ... and stops on the pager's last page,
when `maxItems` is reached, when a page brings no listing not already seen, or
(newest sort, sold dropped) after three pages with nothing for sale. Past the
last page Bobaedream answers 200 with the same total and no rows - no 404 - so
the actor stops on the empty page. There is no page cap.

### Output

| field | meaning |
|---|---|
| `change` | `new`, `price_drop`, `price_rise` or `unchanged` against the previous run of this search - see **Change tracking** |
| `listing_id`, `url`, `market` | Bobaedream's listing number (`785410`), the detail page, and `domestic` or `imported` |
| `title` | The full title as printed, Korean: maker, model, trim |
| `maker`, `maker_en`, `model` | The maker the title starts with (`현대` / `Hyundai`) and the rest of the title. `maker` is null when the title starts with a coach-builder's own name (e.g. 유니캠프); `model` is then the whole title |
| `subtitle` | The dealer's one-line pitch |
| `price_krw` | Asking price in won, a whole number: "1,250 만원" is `12500000` |
| `price_man_won` | The same price as printed, in 만원: `1250` |
| `price_note`, `status` | When the row prints a word instead of a price: `상담` ask the dealer (`negotiable`), `계약` under contract (`reserved`), `팔림` sold (`sold`), `만료` listing expired (`expired`), `렌트` for rent (`rent`), `운용리스` / `금융리스` lease (`lease`). With a price, `status` is `available` |
| `first_registration_year`, `first_registration_month`, `model_year` | From the row's "YY/MM" and "(NN년형)". Month is null when the row prints 00 |
| `fuel`, `fuel_ko` | English (`gasoline`, `diesel`, `gasoline_hybrid`, `electric`, `lpg`, `hydrogen`, ...) and as printed (`가솔린+전기`) |
| `mileage_km`, `mileage_unit` | Odometer in km. Bobaedream prints it rounded ("15만km" is `150000`, "9천km" is `9000`); a few imported rows print miles (만ml) and are converted at 1.609344, `mileage_unit: "mi"` |
| `seats`, `cylinders`, `horsepower`, `torque_kgm`, `drivetrain`, `transmission` | The spec chips under the title. `transmission` is `manual` only when the 수동 chip is shown |
| `badges`, `has_video` | Tag chips as printed (튜닝카 tuned, 캠핑카 camper, 올드카 classic, 희귀차 rare, dealer-group names) and whether the photo has a video |
| `region`, `province`, `district` | e.g. `대구 동구` / `대구` / `동구` |
| `registered_month_day`, `registered_date`, `views` | When the dealer listed the car (`10-26`, and with its year `2026-10-26`) and its view count when read. See **Dates** |
| `seller_name`, `seller_type`, `seller_type_ko`, `seller_id`, `seller_url` | The dealer. `seller_type` is `dealer` (딜러) or `private` (개인), null for other tags such as 반복 (kept in `seller_type_ko`) |
| `image_url` | Main photo |
| `query` | The market (and maker) or search URL this row came from |

Everything is read off the list page - no detail page is opened - which is
what keeps a row cheap.

#### Dates

Bobaedream prints a registration date as "10.26", with no year. The actor
counts the year down the list: the date-ordered list runs strictly newest to
oldest (walked end to end, 7,551 rows, no row newer than the one before it), so
the first row is this year's and the year drops by one each time the date jumps
back up (five times, back to 2021). That is exact on a **newest-first walk
that starts at page 1**, which is the default and what a feed does. On any
other walk - a price or year sort, a pasted URL starting on a later page - the
rows have no order to count in, so `registered_date` is `null` and
`registered_month_day` carries the date as printed. `registeredSince` needs the
newest sort for the same reason.

#### `null` is not zero

Every column except `change`, `listing_id`, `url`, `market`, `title`, `status`,
`badges`, `has_video` and `query` can be `null`, and is `null` whenever the row
simply does not print that value - never `0` or an empty string, because a `0`
reads as a measurement. Measured over about 600 rows on seventeen pages
(2026-10-27):

- `price_krw`, `price_man_won` are null on rows with a word instead of a price
  (`price_note`); on imported page 1, 53 of 70 are 상담 (ask the dealer);
- `mileage_km` is null for 미등록 (never registered);
- `maker` is null for coach-builders; `fuel` is null for a fuel word outside the
  mapped list (`fuel_ko` still carries it);
- the spec chips are present on about 2 of 3 rows;
- `seller_*` and `region` are null on some sold rows, which Bobaedream prints
  without a seller block; `seller_type` is null for the 반복 tag.

### Change tracking

Each run remembers what it saw - listing id and price in won - in a named
key-value store on **your** account, `bobaedream-used-cars-watch`, one record
per search (the exact URLs fetched, so a different filter or sort is a
different search). The next run of the same search labels each car:

- `new` - not seen by the previous run of this search;
- `price_drop` / `price_rise` - seen before, and the price moved;
- `unchanged` - seen before at the same price. A price unknown on either side
  (상담, 계약) is never a change.

**The first run of a search has nothing to compare with, so every car is
`new`** - the run log says "change tracking: first run". From the second run
on, the labels mean what they say.

With `changesOnly` on, `unchanged` cars are skipped: not in the dataset and not
charged. `maxItems` still bounds how many cars are read, so a run where nothing
changed reads your window and stops.

### Proxy

**Apify datacenter proxy is the default.** Measured 2026-10-27 from inside
Apify: 10 of 10 datacenter fetches of a results page returned HTTP 200 with
all 70 listings (about 455 KB each). No refusal has been seen. If one does
come back - a 403, 429 or 5xx, or a 200 without the result total - the actor
switches to a new exit address and retries. A page still refused after the
retries is logged as a failure and nothing is charged for it.

### Billing

Pay per event: **$0.0084 per listing row**, plus a fixed actor-start fee per
run. Platform usage - compute and proxy - is included. A listing is charged at
most once per run, even when two of your searches both return it. Sold and
expired listings (unless `includeSold`) and, with `changesOnly`, unchanged
cars are not charged. A run that fails on its own input is not charged at all.

### Limits

- **This is the cyber-store (사이버매장), the dealer showroom**, not
  Bobaedream's separate `mycar` private-seller list.
- **The store is small.** About 2,300 cars are for sale at once and about 12
  new ones appear a day, so a daily feed of the whole market is a dozen rows
  and a full inventory pull is one run of about 2,300.
- A page is about 455 KB for 70 listings (about 6.5 KB a listing when the page
  is full of cars for sale) whatever the filter, because Bobaedream sends its
  whole page chrome with every list; an empty page is still about 140 KB. The
  server sends no compression.
- Oldest-first (`order=S12`) is not offered: it starts about 90 pages deep in
  sold history before the first car for sale.
- New listings arriving while a long walk is running move older ones one slot
  down a page; the actor de-duplicates, so a car can be read twice but never
  charged twice.
- `maker` and `model` are split from the Korean title by matching the maker
  names Bobaedream lists (plus the aliases its titles use: GM대우, 르노삼성,
  쌍용, 도요타); a title starting with anything else keeps no maker.
- The change label compares the **price** only. A new photo or a changed
  pitch is `unchanged`.
- Bobaedream's refusal page has never been observed, so its classification is
  by elimination: anything without the result total is treated as a refusal
  and retried.

# Actor input Schema

## `market` (type: `string`):

Which Bobaedream cyber-store to read: domestic Korean cars (국산차), imported cars (수입차) or both together. Measured 2026-10-27: about 420 domestic and 1,900 imported cars are for sale at any time; the store's date-ordered lists also keep its whole history of sold and expired cars back to 2021 (7,551 domestic and 20,843 imported rows), which are dropped by default. Ignored for Search URLs, which carry their own market.

## `makers` (type: `array`):

Optional. Only these makers, one per line, in English or Korean: Hyundai, Kia, Genesis, Toyota, Mercedes-Benz, BMW, Porsche, Ferrari, 현대, 벤츠, ... Each maker is its own search sharing the Max listings budget, in order. A name that is not in Bobaedream's maker list for the chosen market is skipped and logged. Leave empty for every maker.

## `fuels` (type: `array`):

Optional. Only these fuels, one per line, from: gasoline, diesel, lpg, gasoline_lpg, gasoline_cng, gasoline_hybrid, lpg_hybrid, diesel_hybrid, cng, electric, hydrogen, other. Several fuels are OR-ed. Leave empty for all fuels.

## `yearMin` (type: `integer`):

Optional. Lowest car year (연식) as Bobaedream's own year filter counts it, e.g. 2020. Leave empty for no lower bound.

## `yearMax` (type: `integer`):

Optional. Highest car year (연식) as Bobaedream's own year filter counts it, e.g. 2024. Leave empty for no upper bound.

## `priceMin` (type: `integer`):

Optional. Lowest asking price in 만원 (units of 10,000 won): 1000 is 10,000,000 won. Bobaedream's price filter drops every listing with no price on file, which includes most imported cars listed as 상담 (ask the dealer): a 0 to 999,999 range keeps 5,691 of 20,843 imported rows.

## `priceMax` (type: `integer`):

Optional. Highest asking price in 만원 (units of 10,000 won): 3000 is 30,000,000 won. Bobaedream's price filter drops every listing with no price on file, which includes most imported cars listed as 상담 (ask the dealer): a 0 to 999,999 range keeps 5,691 of 20,843 imported rows.

## `mileageMin` (type: `integer`):

Optional. Lowest odometer reading in km. Leave empty for no lower bound.

## `mileageMax` (type: `integer`):

Optional. Highest odometer reading in km, e.g. 100000. Leave empty for no upper bound.

## `searchUrls` (type: `array`):

Optional. Bobaedream cyber-store list URLs copied from your browser after you set any filters on the site (model, grade, region, colour, options, body type), e.g. https://www.bobaedream.co.kr/cyber/CyberCar.php?gubun=I\&maker_no=21. Must be a /cyber/CyberCar.php list; a page=3 parameter is kept and the run starts there. Single-car pages and other sites are skipped and logged. When you give URLs and leave every filter above empty and the market on domestic, only the URLs run.

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

Newest registration first is the default and the right order for a new-listing feed; it is the only order that also holds sold and expired cars (as history, dropped unless 'Include sold'), and the only one registered dates and 'Registered since' work with. Every other order lists only the cars still for sale: 424 domestic and 1,878 imported on 2026-10-27, in 7 and 27 pages, so reading them is the cheapest way to take the whole current inventory. A search URL that already carries an order parameter keeps its own.

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

Stop after reading this many listings in total, shared across every search, in order. Bobaedream shows 70 listings per page, so up to 70 costs one page request. For a feed this is the window watched: 'the newest 100'. With 'Only changes' on, listings read but unchanged since the last run are skipped and not charged, and the run still stops here. Sold and expired listings dropped by default do not count.

## `registeredSince` (type: `string`):

Optional, YYYY-MM-DD in Korean time. Skip listings the dealer registered before this date; the run stops at the first older listing, so a daily feed with this set reads only the pages it needs. Needs the newest-registered-first sort. Bobaedream prints the date without a year; the actor counts the year down the list from page 1, so it is exact on a walk that starts there and absent (registered_date null, registered_month_day kept) on any other walk.

## `includeSold` (type: `boolean`):

The date-ordered lists are mostly history: of 7,551 domestic rows, 7,127 are no longer for sale (sold 팔림, expired 만료, under contract 계약), back to 2021. Sold and expired rows are dropped by default, not charged and not remembered; a newest-first walk also ends once three pages in a row hold nothing left to read. Turn on to get them with status sold or expired. Rows under contract (계약), ask-the-dealer (상담) and lease/rent are always kept. Has no effect on the price, year and mileage sorts, which hold only cars for sale.

## `changesOnly` (type: `boolean`):

Output (and pay for) only listings that are new since the previous run of the same search, or whose price went down or up. The first run of a search has nothing to compare with, so it labels every listing new and outputs all of them; the memory is kept per search in a named key-value store on your account (bobaedream-used-cars-watch). Leave off to get every listing, each still labelled new / price_drop / price_rise / unchanged.

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

Apify datacenter proxy by default. Measured 2026-10-27: bobaedream.co.kr answered Apify datacenter exits from inside the platform with HTTP 200 and the full page on 10 of 10 requests. Switch to RESIDENTIAL only if runs start reporting refusals.

## Actor input object example

```json
{
  "market": "domestic",
  "sort": "newest",
  "maxItems": 100,
  "includeSold": false,
  "changesOnly": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `listings` (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 = {
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("superslowsloth/bobaedream-used-cars").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 = { "proxyConfiguration": { "useApifyProxy": True } }

# Run the Actor and wait for it to finish
run = client.actor("superslowsloth/bobaedream-used-cars").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 '{
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call superslowsloth/bobaedream-used-cars --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,superslowsloth/bobaedream-used-cars"
        }
    }
}
```

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/h5cKpBlD2taNv7A8h/builds/kLgG7NPGeSbobmP40/openapi.json
