# Ohouse Scraper (오늘의집) - Furniture & Interior Products, Rankings (`magenta_courser/ohouse-scraper`) Actor

Pick a mode and get Ohouse (오늘의집, ohou.se) store products as flat rows: realtime or all-time best rankings, category lists, keyword search results or product pages, with price, discount, rating, reviews, scraps, delivery and sold-out status, plus rank and price change since your last run.

- **URL**: https://apify.com/magenta_courser/ohouse-scraper.md
- **Developed by:** [SUNGHWAN CHO](https://apify.com/magenta_courser) (community)
- **Categories:** E-commerce, Business
- **Features:** 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

## Ohouse Scraper (오늘의집) - Furniture & Interior Products, Rankings

Pick a mode and get products from the Ohouse store (오늘의집, ohou.se - Korea's largest furniture and interior commerce app) as flat JSON rows: the **best-seller rankings** (실시간 베스트 / 역대 베스트), **category lists** (e.g. 가구 in 판매순), **keyword search results** or **product pages**, each with price, original price, discount, coupon price, rating, review count, scrap (saves) count, delivery and sold-out status. On a schedule, every row also tells you the rank and price change since your last run.

It is built for furniture and home-goods sellers, brands and agencies who check "where is my sofa in the Ohouse best-seller list today, and did the competitor cut the price?" every day, and for analysts researching Korean interior and home-living trends. No login and no browser; the default datacenter proxy worked without blocks in our tests.

### What you get

One row per product (`type: "product"`). Every row has every field; values that do not exist for a mode are `null`.

| Field | Type | Description |
|---|---|---|
| `mode`, `listType` | string | Mode used and the list kind: `rankingRealtime`, `rankingAllTime`, `search`, `category` or `product`. |
| `keyword`, `categoryId`, `categoryName`, `sort` | string | Which list the row came from. |
| `rank` | number | Position in the list (1 = top). `null` in products mode (`inputIndex` is the input order). |
| `productId`, `name`, `brand`, `brandId` | string | Ohouse product ID, Korean product name, brand name and ID. |
| `price`, `originalPrice`, `discountRate` | number | Selling price, price before discount (KRW) and discount % as shown on the site. |
| `couponPrice` | number | Price after the product coupon when Ohouse shows one. |
| `rating`, `reviewCount` | number | Rating (0-5) and review count. |
| `scrapCount`, `userPhotoCount` | number | How many users saved (스크랩) the product and how many user photos it has (counts only). |
| `qaCount` | number | Q\&A count (products mode only). |
| `isSoldOut`, `isSelling`, `isDiscontinued` | boolean | Stock and sale status. |
| `isFreeDelivery`, `deliveryBadge`, `deliveryService`, `isDepartureToday` | mixed | Delivery: badge `FREE` / `CONDITIONAL_FREE` / `CHARGE`, service `OHOUSE` (오늘의집 배송) / `NORMAL` / `SELLER`, ships today. |
| `deliveryFee`, `freeDeliveryThreshold`, `isRegionalDeliveryFee` | mixed | Products mode only. |
| `isSpecialPrice`, `isOverseasPurchase`, `isAd` | boolean | Special-price flag, overseas purchase, sponsored result (`isAd` in search only). |
| `categoryPath`, `leafCategoryId`, `goodsStatus` | string | Products mode only: full category path, leaf category and Ohouse sale status. |
| `imageUrl`, `url`, `listUrl` | string | Main image, product page and the list page the row came from. |
| `previousRank`, `rankChange`, `isNewEntry` | number, number, boolean | Rank in the last completed run of the same list, difference (positive = moved up) and whether the product is new in the list. |
| `previousPrice`, `priceChange` | number | Price last time and the difference (negative = cheaper now). |
| `previousReviewCount`, `reviewCountChange`, `previousIsSoldOut` | mixed | Review count and sold-out state last time. |
| `previousScrapedAt`, `scrapedAt` | string | Time of the compared run and this run. |
| `rankingUpdatedAt` | string | Realtime ranking only: when Ohouse last refreshed it. |
| `totalResults` | number | Search and category: total products Ohouse reports for the list. |
| `schemaVersion`, `source`, `type` | mixed | `1`, `ohouse`, `product`. |

The `RUN_SUMMARY` record in the run's key-value store has one entry per list with `status` (`completed`, `partial`, `failed`, `budgetLimited`, `notStarted`), `stopReason`, `productsSaved` and `ranksScanned`.

### Sample output

A real row from a `changesOnly` re-run of the 가구 (furniture) category in 판매순 (`weekly_buy`), a few minutes after the first run (2026-10-30). The review count went up by 1, which is why the row was saved:

```json
{
  "schemaVersion": 1,
  "source": "ohouse",
  "type": "product",
  "mode": "category",
  "listType": "category",
  "keyword": null,
  "categoryId": "10000000",
  "categoryName": "가구",
  "sort": "weekly_buy",
  "rank": 8,
  "productId": "3898593",
  "name": "코타 호텔 침대, 수납형, SS/Q,K/LK",
  "brand": "오늘의집 layer",
  "brandId": "100651",
  "price": 760000,
  "originalPrice": 760000,
  "discountRate": 0,
  "couponPrice": 722000,
  "rating": 4.7,
  "reviewCount": 188,
  "scrapCount": 7736,
  "userPhotoCount": 149,
  "qaCount": null,
  "isSoldOut": false,
  "isSelling": true,
  "isDiscontinued": false,
  "isFreeDelivery": true,
  "deliveryBadge": "FREE",
  "deliveryService": "OHOUSE",
  "isDepartureToday": false,
  "deliveryFee": null,
  "freeDeliveryThreshold": null,
  "isRegionalDeliveryFee": null,
  "isSpecialPrice": true,
  "isOverseasPurchase": false,
  "isAd": null,
  "categoryPath": null,
  "leafCategoryId": null,
  "goodsStatus": null,
  "imageUrl": "https://prs.ohouse.com/apne2/any/uploads/productions/v1-472000278302720.jpg",
  "url": "https://store.ohou.se/goods/3898593",
  "previousRank": 8,
  "rankChange": 0,
  "isNewEntry": false,
  "previousPrice": 760000,
  "priceChange": 0,
  "previousReviewCount": 187,
  "reviewCountChange": 1,
  "previousIsSoldOut": false,
  "previousScrapedAt": "2026-10-30T10:19:47.237Z",
  "rankingUpdatedAt": null,
  "inputIndex": null,
  "totalResults": 297439,
  "listUrl": "https://ohou.se/store/category?category_id=10000000&order=weekly_buy",
  "scrapedAt": "2026-10-30T10:26:51.358Z"
}
```

### Use cases

- **Rank tracking for furniture and home-goods sellers.** Schedule your category in `weekly_buy` (판매순) or a keyword search daily and read `rankChange` and `isNewEntry` to see where your products and competitors stand.
- **Competitor price and coupon monitoring.** `price`, `couponPrice`, `discountRate` and `priceChange` show who cut a price or added a coupon; `outputMode: "changesOnly"` returns only the products that moved.
- **Trend research on Korean interior products.** The realtime and all-time best rankings plus `scrapCount` (saves) and `userPhotoCount` show which products Korean consumers are saving and posting.
- **Catalog and stock checks for your own listings.** `mode: "products"` with your product URLs returns price, sale status, delivery fee and Q\&A count per product.
- **Sourcing for overseas home-decor shops.** Search Korean keywords such as `암막커튼` (blackout curtain) or `조명` (lighting) and export the organic results with ratings and prices.

### How to use

#### In the Apify Console

Open the Actor, choose a `mode`, fill in `keywords`, `categories` or `productUrls` as needed and click **Start**. With no input you get the site-wide realtime best ranking (100 products). Add a **Schedule** so the change fields fill in from the second run.

| Field | Used in | Description |
|---|---|---|
| `mode` | all | `ranking` (default), `search`, `category` or `products`. If empty: `products` when `productUrls` is set, `search` when `keywords` is set. |
| `rankingType` | ranking | `realtime` = 실시간 베스트 (site-wide), `allTime` = 역대 베스트 (site-wide or per category). Default `realtime`, or `allTime` when `categories` is set. |
| `keywords` | search | Store search keywords, e.g. `소파` (sofa), `책상` (desk), `암막커튼` (blackout curtain). |
| `categories` | category, ranking | Category ID (`10000000`), category URL, or a top-level name (`가구` / `furniture`, `패브릭` / `fabric`, `조명` / `lighting`, ...). |
| `productUrls` | products | `https://store.ohou.se/goods/767440`, `https://ohou.se/productions/767440/selling` or `767440`. |
| `sort` | search, category | `popular` 추천순 (default), `weekly_buy` 판매순, `review` 리뷰많은순, `min_cost` 낮은가격순, `max_cost` 높은가격순, `recent` 최신순, `card` 유저사진 많은순. |
| `maxItems` | lists | Products per list, default 100. Rankings have 100 products. |
| `compareWithLastRun` | all | Default `true`: add rank and price change fields. |
| `outputMode` | all | `all` (default) or `changesOnly`. |
| `historyStoreName` | all | Key-value store for the history, default `ohouse-history`. Use one per project or client. |
| `proxyConfiguration` | all | Default Apify datacenter proxy. Switch to residential KR only if you see blocks. |
| `maxRequests`, `maxRunMinutes` | all | Safety limits; the run stops and keeps what it saved. |

Top-level category IDs: 가구 10000000, 패브릭 18000000, 가전·디지털 14000000, 주방용품 16000000, 식품 31000000, 데코·식물 11000000, 조명 28000000, 수납·정리 13000000, 생활용품 12000000, 생필품 23000000, 유아·아동 27000000, 반려동물 15000000, 캠핑·레저 32000000, 공구·DIY 19000000, 인테리어시공 17000000, 렌탈·구독 26000000, 장보기 33000000, 크리스마스 35000000. For any other category, copy the number after `category_id=` from the ohou.se address bar or paste the URL.

```json
{ "mode": "category", "categories": ["가구", "패브릭"], "sort": "weekly_buy", "maxItems": 200 }
```

```json
{ "mode": "search", "keywords": ["소파", "책상"], "maxItems": 100, "outputMode": "changesOnly" }
```

```json
{ "mode": "products", "productUrls": ["https://store.ohou.se/goods/767440"] }
```

#### API (curl)

```bash
curl -X POST "https://api.apify.com/v2/acts/magenta_courser~ohouse-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode": "ranking", "rankingType": "realtime", "maxItems": 50}'
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("magenta_courser/ohouse-scraper").call(
    run_input={"mode": "category", "categories": ["가구"], "sort": "weekly_buy", "maxItems": 100}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["rank"], item["rankChange"], item["brand"], item["name"], item["price"])
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('magenta_courser/ohouse-scraper').call({
    mode: 'search', keywords: ['소파'], sort: 'weekly_buy', maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => !i.isAd).map((i) => [i.rank, i.name, i.price, i.reviewCount]));
```

#### AI agents and MCP

Add the Apify MCP server (`https://mcp.apify.com`) to Claude, Cursor or another MCP client and name `magenta_courser/ohouse-scraper` as a tool. The inputs an agent needs are `mode` plus `keywords` or `categories` (nothing at all for the realtime ranking). "What are the 20 best-selling sofas on Ohouse right now?" maps to `{"mode": "search", "keywords": ["소파"], "sort": "weekly_buy", "maxItems": 20}`. Rows are flat, prices are numbers in KRW and missing values are `null`.

### Pricing

Pay per result: **$0.0015 per product row** saved, plus $0.00005 per run start (256 MB). Lists or products that fail are not charged, and with `changesOnly` unchanged products are not saved and not charged. If the run reaches your maximum cost per run it stops and the status message says how many products were saved.

Examples: the realtime Top 100 every day is 100 × $0.0015 = $0.15 per day, about **$4.50 per month**. Tracking 100 products in a category with `changesOnly` costs $0.15 on the first run and then only the changed rows; in a busy category where half the rows change daily that is about $2.25 per month.

### FAQ

**Do I need an Ohouse account or API key?**
No. The Actor reads the public store pages that ohou.se shows every visitor. It does not log in and collects no reviews, reviewer names, user photos or other personal data.

**Which list is the Ohouse "category best seller" list?**
Two options: `mode: "ranking"` with `categories` gives Ohouse's all-time best (역대 베스트, top 100) of that category; `mode: "category"` with `sort: "weekly_buy"` gives the category list in 판매순 (recent sales order), as deep as `maxItems` allows.

**How often is the realtime ranking refreshed, and how often should I run this?**
Ohouse refreshes the realtime best list during the day and the row carries that time in `rankingUpdatedAt`. For a daily trend history one run per day is enough; for intraday moves run every few hours.

**Why are `rankChange` and `priceChange` null?**
They fill in from the second completed run of the same list (same mode, keyword or category, sort and `historyStoreName`). Products mode keeps one baseline per product. `isNewEntry: true` means the product was not in the previous list within the depth that run covered.

**What happens if Ohouse blocks the requests?**
The run stops after 10 blocked requests in a row, keeps what it saved and is not charged for the missing products; failed lists are marked in `RUN_SUMMARY`. If you see blocks, switch `proxyConfiguration` to Apify residential, country KR. If nothing at all could be scraped the run is marked failed.

**Can I get options (colors, sizes) and their prices?**
Not yet. Open an issue if you need it.

**오늘의집 판매순 순위를 매일 추적할 수 있나요?**
네. `mode: "category"` + `sort: "weekly_buy"` 또는 검색어를 넣고 스케줄로 매일 실행하면 두 번째 실행부터 순위 변화·가격 변화·리뷰 수 변화가 채워지고, `changesOnly`로 변동 상품만 받을 수 있습니다.

**Does search include sponsored products?**
Organic results are returned with `isAd` marking sponsored rows; recommendation carousels ("오직, 오늘의집에서", "새로운 취향을 발견해보세요") are skipped.

### 한국어 안내

오늘의집(ohou.se) 스토어의 실시간 베스트·역대 베스트 랭킹, 카테고리 목록(추천순·판매순·리뷰순 등), 검색 결과, 상품 상세 페이지를 모드별로 받아오는 Actor입니다. 상품마다 가격, 정가, 할인율, 쿠폰가, 평점, 리뷰 수, 스크랩 수, 유저 사진 수, 배송(무료배송·오늘의집 배송·오늘출발), 품절 여부가 한 행으로 나옵니다. 스케줄로 실행하면 두 번째 실행부터 지난 실행 대비 순위 변화(`rankChange`), 가격 변화(`priceChange`), 리뷰 수 변화가 채워지고, `outputMode: "changesOnly"`로 변동 상품만 저장·과금할 수 있습니다.

가격은 상품 1행당 $0.0015이며, 실시간 베스트 100개를 매일 받으면 한 달 약 $4.50입니다. 실패한 목록은 과금되지 않습니다. 로그인은 필요 없고 기본 데이터센터 프록시로 동작했습니다. 주의: 리뷰 본문·작성자·유저 사진은 수집하지 않으며(개수만), 옵션별 가격은 아직 지원하지 않습니다.

### Notes

- Rankings have 100 products. The realtime ranking is site-wide only; Ohouse ignores categories for it.
- `discountRate` is rounded down as on the site. `couponPrice` appears for rankings, categories and product pages when Ohouse shows a coupon.
- Ohouse can change its website at any time. If a run fails with "unexpected format", please open an issue.
- Collects public product data only - no login, no reviews, no personal data. You are responsible for checking Ohouse's terms of use for your purpose.

### Need another field or feature?

Tell us in the **Issues** tab: a missing field, another input mode, a different output format. We aim to ship requested fields and features within a week, and we answer every issue.

# Actor input Schema

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

What to scrape. ranking = Ohouse best-seller ranking (top 100), search = store search results for "keywords", category = product list of "categories", products = product pages from "productUrls". If empty: products when productUrls is set, otherwise search when keywords is set, otherwise ranking.

## `rankingType` (type: `string`):

Ranking mode only. realtime = 실시간 베스트, the site-wide ranking Ohouse refreshes during the day (no category filter). allTime = 역대 베스트, available site-wide and per category (set "categories"). Default: realtime, or allTime when categories are set. Both lists have 100 products.

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

Search mode. Store search keywords, one per line, as a Korean shopper types them, e.g. 소파 (sofa), 책상 (desk), 암막커튼 (blackout curtain). A pasted Ohouse search URL also works (its query is used). Only the organic product results are returned; recommendation carousels are skipped.

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

Category mode, or all-time ranking per category. Category ID (e.g. 10000000), category URL (https://ohou.se/store/category?category_id=10000000) or a top-level name: 가구 furniture, 패브릭 fabric, 가전·디지털 appliances, 주방용품 kitchen, 식품 food, 데코·식물 deco, 조명 lighting, 수납·정리 storage, 생활용품 household, 생필품 essentials, 유아·아동 kids, 반려동물 pets, 캠핑·레저 camping, 공구·DIY tools, 인테리어시공 remodeling, 렌탈·구독 rental, 장보기 groceries, 크리스마스 christmas. For sub-categories copy the category_id from the Ohouse URL.

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

Products mode. Ohouse product URLs or IDs, one per line, e.g. https://store.ohou.se/goods/767440, https://ohou.se/productions/767440/selling or 767440. Adds category path, delivery fee, free-delivery threshold, Q\&A count and sale status.

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

Search and category mode: the order of the list, as on the website. weekly_buy (판매순) is the category best-seller list.

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

Products 1 to maxItems of each list (each keyword, category or ranking). Rankings have 100 products. You pay per saved product row, so this is also your row count per list.

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

Add previousRank, rankChange (positive = moved up), isNewEntry, previousPrice, priceChange and reviewCountChange, compared with the last completed run of the same list (or the same product in products mode). Kept in a named key-value store in your account, so scheduled runs line up automatically.

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

changesOnly saves (and charges) only products that are new in the list or whose rank, price, review count or sold-out status changed since the last completed run. The first run has nothing to compare with and saves everything. Needs "Compare with last run".

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

Named key-value store that keeps the last ranks and prices. Use a different name for each separate tracking project.

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

Default: Apify datacenter proxy, which worked without blocks in our tests. If requests get blocked, switch to Apify residential, country KR (South Korea).

## `maxRequests` (type: `integer`):

Upper limit on HTTP requests for the whole run, retries included. Default: 2 per planned page + 5. When it is used up the run stops and keeps what it saved.

## `maxRunMinutes` (type: `integer`):

The run stops sending new requests after this many minutes (default 60) and keeps what it saved. It also stops after 10 blocked requests in a row.

## Actor input object example

```json
{
  "mode": "ranking",
  "keywords": [],
  "sort": "popular",
  "maxItems": 100,
  "compareWithLastRun": true,
  "outputMode": "all",
  "historyStoreName": "ohouse-history",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per product (type = product) with rank in the requested list, price, rating, reviews, delivery and change since the last run.

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

Run status and one entry per list (status completed, partial, failed, budgetLimited or notStarted, stopReason, productsSaved, ranksScanned). Failed lists and products 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 = {
    "mode": "ranking",
    "keywords": [],
    "maxItems": 100,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("magenta_courser/ohouse-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": "ranking",
    "keywords": [],
    "maxItems": 100,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("magenta_courser/ohouse-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": "ranking",
  "keywords": [],
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call magenta_courser/ohouse-scraper --silent --output-dataset

```

## MCP server setup

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