# Korean Furniture Prices: Hanssem, Livart, Casamia (한샘·리바트·까사미아) (`magenta_courser/korea-furniture-prices`) Actor

Pick furniture categories (sofa, bed, mattress, desk...) or keywords and get product prices from Hanssem Mall, Hyundai Livart and Casamia in one table: price, original price, discount, rating, reviews, sold-out flag, with price change since your last run.

- **URL**: https://apify.com/magenta_courser/korea-furniture-prices.md
- **Developed by:** [SUNGHWAN CHO](https://apify.com/magenta_courser) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 products

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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?

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

## Korean Furniture Prices: Hanssem, Livart, Casamia (한샘·리바트·까사미아)

Pick furniture categories (sofa, bed, mattress, desk...) or search keywords and get **product prices from Korea's three big furniture brand malls in one table**: Hanssem Mall (한샘몰), Hyundai Livart Mall (현대리바트) and Casamia Mall (까사미아, guud.com). Every row has price, original price, discount, rating, review count, sold-out flag, image and product URL. Schedule it and each row also tells you **how the price changed since your last run**.

- No login, no browser: reads the same public product lists the store websites show to every visitor.
- One shared schema for all three stores, so you can compare a sofa at Hanssem with one at Livart without any mapping.
- One store failing (site maintenance, a wrong category URL) never fails the whole run; you are only charged for products actually saved.

### What you can use it for

- **Price monitoring** of Korean furniture (가구 가격 비교, 소파 가격, 침대 가격, 매트리스 할인) for retailers, importers and marketplaces.
- **Promotion tracking**: daily runs show which brand started a sale (할인, 특가, 쓱데이) and by how much.
- **Assortment research**: what each brand sells in a category, at which price points, and which items are sold out (품절).
- **Feeding AI agents and dashboards** with flat, typed JSON.

### Input

| Field | What it does |
|---|---|
| `stores` | `hanssem`, `livart`, `casamia` (empty = all three) |
| `categories` | Shared presets mapped to each store's own category: `sofa`, `bed`, `mattress`, `diningTable`, `diningChair`, `wardrobe`, `dresser`, `storage`, `tvStand`, `livingTable`, `desk`, `bookcase`, `chair` |
| `categoryUrls` | Any category page URL of the three stores, e.g. `https://store.hanssem.com/category/20128`, `https://www.hyundailivart.co.kr/c/C400002394`, `https://www.guud.com/shop/goodsList?f_c=5081` |
| `keywords` | The stores' own product search, e.g. `리클라이너`, `모션베드`, `식탁` (Korean works best) |
| `sort` | `popular` (store default), `newest`, `priceLow`, `priceHigh`, `reviews` |
| `maxItems` | Max products per store per category or keyword (default 100) |
| `compareWithLastRun` | Add previous price / price change fields (default on) |
| `outputMode` | `all` or `changesOnly` (only new products and products whose price or sold-out state changed) |
| `historyStoreName` | Named key-value store that keeps the last prices (default `korea-furniture-price-history`) |
| `proxyConfiguration` | Apify Proxy; the default datacenter proxy works for all three stores |

Example:

```json
{
  "stores": ["hanssem", "livart", "casamia"],
  "categories": ["sofa", "mattress"],
  "keywords": ["리클라이너"],
  "maxItems": 100,
  "sort": "popular"
}
```

### Output

One row per product per list. Example from a real first run (Hanssem, sofa; the change fields are `null` because there was no earlier run yet):

```json
{
  "store": "hanssem",
  "storeName": "Hanssem Mall",
  "listType": "category",
  "category": "sofa",
  "categoryId": "20081",
  "categoryName": "거실 > 소파",
  "productCategory": null,
  "keyword": null,
  "sort": "popular",
  "rank": 1,
  "productId": "1138382",
  "name": "엠마 컴포트 스윙 천연가죽 소파 3인(2종/택1)",
  "brand": "한샘",
  "price": 1099000,
  "originalPrice": 1418000,
  "discountRate": 22,
  "rating": 4.7,
  "reviewCount": 12,
  "isSoldOut": false,
  "imageUrl": "https://image.hanssem.com/hsimg/gds/2100/1138/1138382_A1.jpg?v=20260703135926",
  "url": "https://store.hanssem.com/goods/1138382",
  "previousPrice": null,
  "priceChange": null,
  "priceChangePercent": null,
  "previousIsSoldOut": null,
  "isNewProduct": null,
  "previousScrapedAt": null,
  "listUrl": "https://store.hanssem.com/category/20081",
  "scrapedAt": "2026-10-30T10:19:14.524Z"
}
```

Field notes:

- Prices are numbers in KRW. `price` is the price the store shows on its list page (after the store's own discount); `originalPrice` is the crossed-out list price (equal to `price` when there is no discount).
- `rating` is `null` when a product has no reviews. **Casamia's list does not publish ratings**, so `rating` is always `null` for Casamia; `reviewCount` is real.
- Livart ratings and review counts come from the review widget the Livart site uses.
- `productCategory` is the store's own sub-category of the product (Casamia only).
- `rank` is the position in the store list for the chosen `sort`.
- Missing values are `null`, never empty strings.

#### Price change since last run

With `compareWithLastRun` on (default), the Actor remembers the last **completed** run of each store list + sort order in a named key-value store. Next run adds `previousPrice`, `priceChange`, `priceChangePercent`, `previousIsSoldOut`, `isNewProduct` and `previousScrapedAt`. The first run has no baseline, so these are `null`. Use `outputMode: changesOnly` on a daily schedule to get (and pay for) only what changed.

#### Run summary

The `RUN_SUMMARY` record in the run's key-value store lists every store list with `status` (completed, partial, failed, budgetLimited, notStarted), `stopReason`, products saved and the store's total count, plus totals per store.

### Pricing

Pay per event: you pay per saved product row. Failed lists, failed pages and products skipped by `changesOnly` are free. If you set a maximum cost per run, the Actor stops cleanly at that limit and tells you how many products it saved.

### Tips and limits

- Each category gives up to `maxItems` products **per store**: 3 stores x 2 categories x 100 = up to 600 rows.
- Store category trees differ, so presets map to each store's closest category (for example Casamia's `sofa` includes recliners). Use `categoryUrls` for an exact store category.
- If a store is under maintenance or slow, that store's lists are marked failed in `RUN_SUMMARY` and the others still finish.
- This Actor collects public product information only: no customer data, no reviewer names, no login.

### Korean keywords

한샘몰 크롤링, 현대리바트 크롤러, 까사미아 가격, 가구 가격 비교, 가구 최저가, 소파 가격 추적, 침대 매트리스 가격, 가구 할인 모니터링, 한샘 리바트 까사미아 상품 데이터, 가구 쇼핑몰 스크래퍼

# Actor input Schema

## `stores` (type: `array`):

Which online malls to scrape: hanssem = Hanssem Mall (한샘몰, store.hanssem.com), livart = Hyundai Livart Mall (현대리바트), casamia = Casamia Mall (까사미아, guud.com). Leave empty for all three.

## `categories` (type: `array`):

Furniture categories, mapped to the matching category of every selected store. Each category gives up to "maxItems" products per store.

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

Any category page of the three stores, e.g. https://store.hanssem.com/category/20128, https://www.hyundailivart.co.kr/c/C400002394 or https://www.guud.com/shop/goodsList?f_c=5081. Each URL is scraped in its own store.

## `keywords` (type: `array`):

Search each selected store's own product search, e.g. "리클라이너" (recliner) or "모션베드". Korean keywords work best.

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

Order of each store list. rank in the output follows this order.

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

Maximum products per store and category (or keyword). 3 stores x 1 category x 100 = up to 300 products.

## `compareWithLastRun` (type: `boolean`):

Adds previousPrice, priceChange, priceChangePercent, previousIsSoldOut and isNewProduct compared with the last completed run of the same store list and sort order (kept in a named key-value store).

## `outputMode` (type: `string`):

changesOnly saves (and charges) only products that are new or whose price or sold-out state changed since the last run. The first run of each list saves everything.

## `historyStoreName` (type: `string`):

Named key-value store that keeps the last prices. Use a different name to keep separate histories (e.g. per schedule).

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

Apify Proxy. The default datacenter proxy works for all three stores; switch to RESIDENTIAL with country KR only if a store starts blocking.

## Actor input object example

```json
{
  "stores": [
    "hanssem",
    "livart",
    "casamia"
  ],
  "categories": [
    "sofa"
  ],
  "sort": "popular",
  "maxItems": 30,
  "compareWithLastRun": true,
  "outputMode": "all",
  "historyStoreName": "korea-furniture-price-history",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per product per list (store + category or keyword), with price, discount, rating, reviews, sold-out flag and price change since the last run.

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

Per store and per list: status (completed, partial, failed, budgetLimited, notStarted), stopReason, productsSaved, store total and errors. Failed lists are not charged.

# 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 = {
    "stores": [
        "hanssem",
        "livart",
        "casamia"
    ],
    "categories": [
        "sofa"
    ],
    "maxItems": 30,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("magenta_courser/korea-furniture-prices").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 = {
    "stores": [
        "hanssem",
        "livart",
        "casamia",
    ],
    "categories": ["sofa"],
    "maxItems": 30,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("magenta_courser/korea-furniture-prices").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 '{
  "stores": [
    "hanssem",
    "livart",
    "casamia"
  ],
  "categories": [
    "sofa"
  ],
  "maxItems": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call magenta_courser/korea-furniture-prices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,magenta_courser/korea-furniture-prices"
        }
    }
}
```

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/Gsi77SDqBRh7CgU7q/builds/jzGxYih60BngzGe2s/openapi.json
