# Kakao Map Scraper - Places Extractor (Official API, No 45 Cap) (`koreadata-lab/kakao-map-places-api`) Actor

Get every Kakao Map place for a keyword or category in a Korean area via the official Kakao Local API, run with your own key. Grid splitting beats the 45-result limit. English categories, romanized names, coordinates, dedup.

- **URL**: https://apify.com/koreadata-lab/kakao-map-places-api.md
- **Developed by:** [Koreadata Lab](https://apify.com/koreadata-lab) (community)
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 places

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

## Kakao Map Scraper - Places Extractor (Official API, No 45 Cap)

A Kakao Map scraper for Korean places: extract **every place** for a keyword or category in an area of Korea from **Kakao Map (카카오맵)** through the **official Kakao Local API**, with names, categories, addresses, phone numbers and coordinates. The API normally stops at **45 results per search**. This actor splits the area into tiles automatically whenever a search hits that cap, so you get the full list for dense areas instead of only the first 45.

> **Live-tested on Apify: YES (2026-10-29).** Keyword "카페", 1 km around Seongsu station, max 100: 87 unique cafes in 8 s, with the category auto-filter on (without it, places that only had "카페" in their name, such as a hair salon, slipped in).

### Why this actor

- **Beats the 45 cap** with recursive quad-tree tiling and de-duplication.
- **English output:** English category path (`Restaurant > Cafe > Coffee shop`), English category group, English region (`Seoul Seongdong-gu`) and a **romanized place name** (`Eonieon Seongsu`) for maps and apps aimed at foreigners.
- **Official API:** no blocking and no proxies.
- **PIPA-aware:** mobile numbers (010/011/016-019), which can belong to individuals, are dropped by default. Business lines are kept.

### Input

```json
{ "query": "카페", "areaMode": "circle", "centerLat": "37.5446", "centerLng": "127.0557", "radiusMeters": 1000, "restApiKey": "YOUR_KAKAO_REST_KEY" }
```

Or use category-only search (`categoryGroupCode`: `CE7` cafe, `FD6` restaurant, `AT4` tourist attraction, `PM9` pharmacy and the other Kakao group codes) or a bounding box (`areaMode: "rect"`, `rect: "minLng,minLat,maxLng,maxLat"`). `maxPlaces` (default 1,000) caps the number of places per run.

### Output

Example (illustrative values), one place:

```json
{
  "placeId": "26338954", "name": "어니언 성수", "nameRomanized": "Eonieon Seongsu",
  "categoryPathKo": "음식점 > 카페 > 커피전문점", "categoryPathEn": "Restaurant > Cafe > Coffee shop",
  "categoryLeafKo": "커피전문점", "categoryLeafEn": "Coffee shop", "categoryGroupCode": "CE7", "categoryGroupEn": "Cafe",
  "phone": "070-7816-2718", "phoneMasked": false,
  "address": "서울 성동구 성수동2가 277-135", "roadAddress": "서울 성동구 아차산로9길 8", "regionEn": "Seoul Seongdong-gu",
  "latitude": 37.544643, "longitude": 127.058389, "distanceMeters": 120,
  "url": "http://place.map.kakao.com/26338954", "query": "카페", "fetchedAt": "2026-10-29T06:00:00.000Z"
}
```

When a place only lists a mobile number, `phone` is `null` and `phoneMasked` is `true`.

### Endpoints used (official)

- `GET https://dapi.kakao.com/v2/local/search/keyword.json`
- `GET https://dapi.kakao.com/v2/local/search/category.json`

Header: `Authorization: KakaoAK {REST_API_KEY}`. Get a key at developers.kakao.com and enable Kakao Map for the app. Daily quotas apply per app.

### Limitations

- **No reviews, ratings, opening hours or menus.** The official Local API does not provide them, and this actor does not scrape place pages.
- Romanization is algorithmic (Revised Romanization, simplified). It is not the official English name of the business.
- English category names come from a static dictionary. Unknown terms are `null`, and the Korean original is always kept.
- Very dense areas may need `maxSplitDepth` 5 to 6. The log warns when a tile is still capped.
- **Kakao terms:** results are for use inside your own service. The Kakao platform terms (Article 11) do not allow copying, publishing or redistributing the information, or selling it, without Kakao's prior consent. You run this actor with your own Kakao key and are responsible for that use.

### API keys (secret inputs)

- `restApiKey` is a **secret input** (`isSecret` in the input schema): Apify stores it encrypted and hides it in the Console and in API responses.
- The actor uses it only in the request headers sent to the official Kakao Local API (`dapi.kakao.com`, `Authorization: KakaoAK ...`). It is **never logged, never written** to the dataset or key-value stores, and never put in URLs.
- Use your own key. If it is exposed, reissue it in Kakao Developers (My Application > App Keys) and update the input.

### Pricing (pay per event)

- `place-result`: **$3.00 per 1,000 places**. Each unique place is charged once per run; duplicates from overlapping tiles are removed before charging.
- Actor start: Apify's synthetic `apify-actor-start` event, a fraction of a cent per run.
- **Platform usage is included.** You pay only the event prices above; the Apify compute of the run is not billed to you separately.
- Set **Max total charge** for a run to cap spend; the actor stops early when it is reached.

### FAQ

**Do I need my own API key?**
Yes, a Kakao REST API key. Sign in at developers.kakao.com, create an application, copy the **REST API key** from App Keys, and turn on Kakao Map (카카오맵) in the app's product settings. Kakao applies a daily quota per app.

**How fresh is the data?**
Each run calls the Kakao Local API live, so you get the places Kakao Map lists at that moment. Nothing is cached between runs.

**Can I schedule it?**
Yes, with an Apify Schedule (for example weekly or monthly) to refresh a place list for an area. Each run returns the full current list, not only changes.

**What does a typical run cost?**
100 places cost about $0.30. The live test above (87 cafes) cost about $0.26. A full 1,000-place run costs about $3.00.

**Is this legal, and where does the data come from?**
The data comes from Kakao's official Local API, called with your own key. No Kakao Map pages are scraped. Kakao's terms limit use to your own service and do not allow redistributing or selling the data without Kakao's consent (see Limitations).

# Actor input Schema

## `query` (type: `string`):

What to search, e.g. 카페, 올리브영, 돈까스, 'Seongsu bakery'. Leave empty to search by category only.

## `categoryGroupCode` (type: `string`):

Kakao category group. Required when no keyword is given.

## `autoCategory` (type: `boolean`):

When the keyword is a generic place type (카페, 맛집, 약국, 호텔...) and no category is chosen, add the matching Kakao category so places that only have the word in their name (e.g. a hair salon called '...카페') are left out.

## `areaMode` (type: `string`):

How the search area is defined.

## `centerLat` (type: `string`):

For circle mode, e.g. 37.5446 (Seongsu-dong).

## `centerLng` (type: `string`):

For circle mode, e.g. 127.0557.

## `radiusMeters` (type: `integer`):

For circle mode. Up to 20,000 m.

## `rect` (type: `string`):

For rect mode: minLng,minLat,maxLng,maxLat (e.g. 127.03,37.53,127.07,37.56).

## `splitIfCapped` (type: `boolean`):

Kakao returns at most 45 places per search. When a search hits the cap, the area is split into 4 tiles recursively until each tile is complete.

## `maxSplitDepth` (type: `integer`):

Each level multiplies tiles by 4. Depth 4 = up to 256 tiles.

## `maxPlaces` (type: `integer`):

Stop after this many unique places.

## `maskMobilePhones` (type: `boolean`):

Drop numbers starting with 010/011/016-019 because they may belong to an individual (Korean PIPA). Business lines are kept.

## `restApiKey` (type: `string`):

Your own REST API key from https://developers.kakao.com (My Application > App Keys). Enable 'Kakao Map' for the app. Daily quota applies per app. Stored encrypted by Apify; sent only in the Authorization header, never logged.

## Actor input object example

```json
{
  "query": "카페",
  "categoryGroupCode": "",
  "autoCategory": true,
  "areaMode": "circle",
  "centerLat": "37.5446",
  "centerLng": "127.0557",
  "radiusMeters": 1000,
  "rect": "",
  "splitIfCapped": true,
  "maxSplitDepth": 4,
  "maxPlaces": 1000,
  "maskMobilePhones": true
}
```

# Actor output Schema

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

All result rows in the default dataset.

# 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 = {
    "query": "카페"
};

// Run the Actor and wait for it to finish
const run = await client.actor("koreadata-lab/kakao-map-places-api").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 = { "query": "카페" }

# Run the Actor and wait for it to finish
run = client.actor("koreadata-lab/kakao-map-places-api").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 '{
  "query": "카페"
}' |
apify call koreadata-lab/kakao-map-places-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,koreadata-lab/kakao-map-places-api"
        }
    }
}
```

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/nKECptsi2Y0QaaFbP/builds/ZiiP8cqxh7TavcRvK/openapi.json
