# Daangn Scraper $1💰 Listings, Sellers, Regions & Categories (`abotapi/daangn-scraper`) Actor

From $1/1K. Scrape Daangn (당근) marketplace listings by keyword and region. Returns 35+ fields per item including price, status, condition, full image set, region, category and seller profile (nickname, score, reviews). Search and URL modes, category and on-sale filters, price range and sort.

- **URL**: https://apify.com/abotapi/daangn-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 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.
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

## Daangn Scraper

Collect structured listing data from Daangn (당근), Korea's largest local marketplace, by keyword and region. The scraper returns rich, ready-to-use records: price, status, condition, the full image set, region, category and the seller profile (nickname, score, review count). Run it by keyword, by region, or by pasting Daangn search and detail URLs, and pipe the results straight into your spreadsheet, database or apps.

### Why This Scraper?

- 35+ fields per listing, including the full image set, region tree, category and the complete seller profile, not just a title and a price.
- Two ways to run: search by keyword + region, or paste any Daangn search or detail URL.
- Server-side category and on-sale filters plus price-range and sort controls.
- One simple limit: set Max items and the run stops there. No confusing second cap.
- Optional detail enrichment adds description, view/chat/favorite counts and the seller profile per item.
- Optional one-click export into Notion, Linear, Airtable or Apify via MCP connectors.
- Runs on the default datacenter proxy on every plan; switch to Residential (country KR) for the most reliable results.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live listing.

| Field | Example |
| --- | --- |
| id | "0000000000" |
| nodeId | "a0b0c0d0e0f0" |
| url | "https://www.daangn.com/kr/buy-sell/sample-a0b0c0d0e0f0/" |
| title | "iPhone 15 256GB Blue" |
| price | 480000 |
| priceText | "480,000원" |
| isFree | false |
| currency | "KRW" |
| status | "Ongoing" |
| condition | "used" |
| content | "Lightly used, battery health 90%." |
| location | "Sample-dong" |
| region.name | "Sample-dong" |
| region.id | "000" |
| category.name | "Digital" |
| category.id | "1" |
| sellerName | "Jane Doe" |
| user.score | 39.2 |
| user.reviewCount | 23 |
| watchesCount | 12 |
| chatRoomsCount | 6 |
| readsCount | 733 |
| createdAt | "2026-01-01T00:00:00.000+09:00" |
| imageUrl | "https://img.example.com/sample\_0.webp" |

### How to Use

Search by keyword in one region:

```json
{
  "mode": "search",
  "searchQueries": ["아이폰"],
  "locations": ["366"],
  "maxItems": 50,
  "fetchDetails": true
}
```

Search several keywords across several regions with a price range:

```json
{
  "mode": "search",
  "searchQueries": ["노트북", "의자"],
  "locations": ["366", "6187"],
  "priceMin": 50000,
  "priceMax": 300000,
  "sortBy": "price_asc",
  "maxItems": 100
}
```

Paste Daangn URLs directly:

```json
{
  "mode": "url",
  "urls": [
    "https://www.daangn.com/kr/buy-sell/s/?search=%EC%95%84%EC%9D%B4%ED%8F%B0&region_id=366",
    "https://www.daangn.com/kr/buy-sell/sample-a0b0c0d0e0f0/"
  ],
  "fetchDetails": true,
  "maxItems": 40
}
```

Track a search over repeated scheduled runs (Incremental mode):

```json
{
  "mode": "search",
  "searchQueries": ["아이폰"],
  "locations": ["366"],
  "incrementalMode": true,
  "emitExpired": true,
  "maxItems": 0
}
```

### Input Parameters

| Field | Type | Description |
| --- | --- | --- |
| mode | string | "search" builds searches from your keywords + regions + filters; "url" uses pasted Daangn URLs. |
| searchQueries | array | Keywords to search for (search mode). Each is scraped independently. |
| locations | array | Numeric Daangn region ids to center the search on. Empty = region resolved from the connection. |
| categoryId | integer | Restrict to one Daangn category id (e.g. 1 Digital, 8 Furniture). Empty = all. |
| onlyOnSale | boolean | Return only listings still on sale (excludes reserved/completed). |
| priceMin | integer | Only listings priced at or above this amount (KRW). |
| priceMax | integer | Only listings priced at or below this amount (KRW). |
| sortBy | string | "recommended", "recent", "price\_asc" or "price\_desc". |
| urls | array | Daangn search or detail URLs (URL mode). Filter fields are ignored. |
| fetchDetails | boolean | Visit each listing page for description, image set, counts and seller profile. |
| maxItems | integer | The single run cap. Stop after this many listings. 0 = unlimited. |
| maxPages | integer | Safety bound on result pages per query. Empty = unlimited; the run stops at Max items. |
| resumeFromRunId | string | Continue one specific interrupted run: paste a previous run id or dataset id and already-collected listings are skipped. |
| incrementalMode | boolean | Track this same search over repeated scheduled runs; returns only NEW/UPDATED/REAPPEARED (and optionally EXPIRED) listings. Default off. |
| stateKey | string | Optional name for the Incremental mode baseline. Empty = auto-derived from your search settings. |
| emitUnchanged | boolean | Incremental mode: also return (and bill) listings with no change since last run. Default off. |
| emitExpired | boolean | Incremental mode: also return (and bill) listings no longer found, once a run completes a full scan. Default off. |
| proxy | object | Connection settings. Datacenter is the default and works on every plan; Residential (country KR) is the most reliable. |
| maxResidentialMB | integer | Residential traffic budget in MB. After the cap the run continues on the lower-cost datacenter proxy (same data). 0 = unlimited. |
| mcpConnectors | array | Optional MCP connectors to export results into (Notion, Linear, Airtable, Apify). |
| notionParentPageUrl | string | Notion page under which item pages are created (Notion connector only). |
| maxNotifyListings | integer | Cap on items written to each connector per run. Does not affect the dataset. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live listing.

```json
{
  "id": "0000000000",
  "nodeId": "a0b0c0d0e0f0",
  "url": "https://www.daangn.com/kr/buy-sell/sample-a0b0c0d0e0f0/",
  "title": "iPhone 15 256GB Blue",
  "content": "Lightly used, battery health 90%.",
  "description": "Lightly used, battery health 90%.",
  "status": "Ongoing",
  "condition": "used",
  "listingType": "FleamarketArticle",
  "price": 480000,
  "priceText": "480,000원",
  "isFree": false,
  "currency": "KRW",
  "countryCode": "KR",
  "createdAt": "2026-01-01T00:00:00.000+09:00",
  "postedAt": "2026-01-01T00:00:00.000+09:00",
  "publishedAt": "2026-01-01T00:00:00.000+09:00",
  "imageUrl": "https://img.example.com/sample_0.webp",
  "images": ["https://img.example.com/sample_0.webp"],
  "location": "Sample-dong",
  "locationName": null,
  "regionSlug": "sample-dong-000",
  "searchQuery": "아이폰",
  "region": { "id": "000", "name": "Sample-dong", "countryCode": "KR" },
  "category": { "id": "1", "name": "Digital" },
  "user": { "nickname": "Jane Doe", "score": 39.2, "reviewCount": 23, "locationName": null },
  "tradingLocation": { "name": "Sample-dong", "isUserInput": null, "latitude": null, "longitude": null },
  "sellerName": "Jane Doe",
  "watchesCount": 12,
  "chatRoomsCount": 6,
  "readsCount": 733
}
```

#### Resume & recurring updates

Two separate features cover two separate needs:

- **`resumeFromRunId`** continues ONE specific interrupted run. Paste the run id or dataset id from a previous run that got cut off (timeout, item cap, connection issue) and this run skips every listing it already collected, so you don't pay to re-scrape and re-download what you already have.
- **`incrementalMode`** tracks the SAME search across many scheduled runs on its own — no id to paste. Turn it on and schedule the actor (e.g. daily); each run compares against a baseline it remembers itself (keyed by your search settings, or your own **State key**) and returns only `changeType: "NEW"`, `"UPDATED"` or `"REAPPEARED"` listings, plus `changedFields`, `firstSeenAt` and `lastSeenAt`. Unchanged listings are neither returned nor billed unless you turn on **Emit unchanged listings**. Listings that disappear are only reported as `"EXPIRED"` (and only if **Emit expired listings** is on) once a run completes a full, uncapped scan of the search — a run limited by Max items (the default is 20) never reports EXPIRED, since it never proved those listings are actually gone.
- The baseline for Incremental mode is keyed on your search settings (mode, keywords, regions, category, on-sale, price range, sort, URLs, fetch details) — **not** on Max items/Max pages/the residential budget/the connector export cap, so raising a limit keeps your existing baseline instead of starting over and re-billing everything.
- **Volatility note:** Daangn listings carry live engagement counters (`chatCount`, `chatRoomsCount`, `favoriteCount`, `readsCount`, `viewCount`, `watchesCount`) and a re-boost timestamp (`boostedAt`) that change from other users' activity, independent of the listing itself. Incremental mode deliberately ignores these (along with seller reputation fields and the search keyword that found the listing) when deciding NEW/UPDATED/UNCHANGED, so a listing isn't reported as "changed" every run just because someone viewed or bumped it. A real change to price, status, condition, title, description or images always still triggers `"UPDATED"`.

#### Export to your apps (MCP connectors)

You can optionally pipe each run's results into the apps you already use through Model Context Protocol (MCP) connectors. Authorize a connector under Apify -> Settings -> API & Integrations, then select it in the mcpConnectors field. Notion receives a rich page per item (set notionParentPageUrl to the parent page); Linear, Airtable and Apify receive a best-effort write or digest. This never changes the dataset output, and any connector error is logged and skipped without affecting the scrape.

### Plan Requirement

This scraper runs on the default datacenter proxy on any plan, including the free tier, and returns the same Daangn data as residential, so it is the recommended default.

For maximum reliability you can switch the proxy to Apify Residential with country KR (requires a plan that includes Residential proxy access). When on residential, set a **Residential traffic budget (MB)** to cap spend: once the budget is reached the run continues on the default datacenter proxy for the rest of the run, with identical results.

# Actor input Schema

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

How to start the scrape. 'search' builds Daangn searches from your keywords + regions + filters. 'url' uses the Daangn search or detail URLs you paste (filter fields below are ignored in URL mode).

## `searchQueries` (type: `array`):

One or more keywords to search Daangn for. Each query is scraped independently.

## `locations` (type: `array`):

Numeric Daangn region ids to center the search on (e.g. '366' for Seocho-4-dong, '6187' for Sincheon-dong). Each query is run for each region. Leave empty to use the region resolved from the connection automatically.

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

Restrict results to one Daangn category id. Examples: 1 Digital, 172 Appliances, 8 Furniture, 7 Living/Kitchen, 4 Baby/Kids, 5 Women's clothing, 14 Men's fashion, 6 Beauty, 3 Sports/Leisure, 2 Hobby/Game, 9 Books, 13 Other. Leave empty for all categories.

## `onlyOnSale` (type: `boolean`):

Return only listings that are still on sale (excludes reserved and completed items).

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

Only return listings priced at or above this amount.

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

Only return listings priced at or below this amount.

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

Order results are returned in.

## `urls` (type: `array`):

Paste Daangn search URLs (https://www.daangn.com/kr/buy-sell/s/?search=...) or item detail URLs (https://www.daangn.com/kr/buy-sell/<slug>-<id>/). Multi-URL supported; filter-mode fields are ignored.

## `fetchDetails` (type: `boolean`):

Adds the description, full image set, category, view/chat/favorite counts and the complete seller profile (score, reviews, profile image) to each listing. Slower; turn off for fast basic listings.

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

THE cap on this run: stop after collecting this many listings (across all queries/URLs). This is the only finite default cap. Set 0 for unlimited.

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

Optional safety bound on how many result pages to walk per query. Defaults to unlimited (leave empty or 0) and does NOT cap the run: the run stops at Max items, never here. Use only to short-circuit a single query's pagination; it never imposes a separate cap and always defers to Max items.

## `resumeFromRunId` (type: `string`):

Paste a previous run id or dataset id to continue an interrupted crawl: listings already collected there are skipped so this run returns only what's missing. A one-off continuation, distinct from Incremental mode below, which tracks a search across many scheduled runs on its own.

## `incrementalMode` (type: `boolean`):

For a scheduled/recurring run of the SAME search: remembers what was collected last time and returns only NEW, UPDATED, REAPPEARED and (optionally) EXPIRED listings. Off by default (returns everything, like a one-off run). Distinct from 'Resume from run/dataset id' above, which continues one specific interrupted run instead of tracking a recurring search.

## `stateKey` (type: `string`):

Optional name for the saved baseline used by Incremental mode. Leave empty to auto-derive one from your search settings (queries, regions, category, filters, sort, URLs, fetch details) — two different filter setups never share a baseline. Set your own to explicitly separate or share monitoring campaigns.

## `emitUnchanged` (type: `boolean`):

When on, Incremental mode also returns listings with no change since the last run (changeType UNCHANGED). Off by default: unchanged listings are neither returned nor billed, only NEW/UPDATED/REAPPEARED/EXPIRED are. Turning this on returns — and bills — every listing every run.

## `emitExpired` (type: `boolean`):

When on, Incremental mode also returns listings that were tracked before but are no longer found (changeType EXPIRED), once a run completes a full scan of the search. Off by default. Turning this on returns — and bills — an extra row per listing that disappeared.

## `proxy` (type: `object`):

Connection used for requests. Datacenter (the default) is the cheapest and works on every plan; Residential with country KR is the most reliable.

## `maxResidentialMB` (type: `integer`):

When using a Residential proxy group, cap residential traffic at this many MB; after the cap the run continues on the lower-cost datacenter proxy, which returns the same Daangn data. 0 = unlimited.

## `mcpConnectors` (type: `array`):

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify -> Settings -> API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write/digest. Leave empty to skip; never changes the dataset output. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "searchQueries": [
    "아이폰"
  ],
  "locations": [
    "366"
  ],
  "onlyOnSale": false,
  "sortBy": "recommended",
  "urls": [
    "https://www.daangn.com/kr/buy-sell/s/?search=%EC%95%84%EC%9D%B4%ED%8F%B0"
  ],
  "fetchDetails": true,
  "maxItems": 20,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxy": {
    "useApifyProxy": true
  },
  "maxResidentialMB": 0,
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (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 = {
    "mode": "search",
    "searchQueries": [
        "아이폰"
    ],
    "locations": [
        "366"
    ],
    "urls": [
        "https://www.daangn.com/kr/buy-sell/s/?search=%EC%95%84%EC%9D%B4%ED%8F%B0"
    ],
    "maxItems": 20,
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/daangn-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",
    "searchQueries": ["아이폰"],
    "locations": ["366"],
    "urls": ["https://www.daangn.com/kr/buy-sell/s/?search=%EC%95%84%EC%9D%B4%ED%8F%B0"],
    "maxItems": 20,
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/daangn-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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",
  "searchQueries": [
    "아이폰"
  ],
  "locations": [
    "366"
  ],
  "urls": [
    "https://www.daangn.com/kr/buy-sell/s/?search=%EC%95%84%EC%9D%B4%ED%8F%B0"
  ],
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/daangn-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=abotapi/daangn-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/SnadC3qCLCYXZ8PSW/builds/7X8AaV4f4ydGjUisx/openapi.json
