# Naver Map Business Listings with Menu & Hours Data (`dataspryva/naver-map-business-listings-with-menu-and-hours`) Actor

Search Naver Map by keyword or place URL and get address, phone, weekly hours, menu with prices, amenities, transit access, booking links, and review scores for each business.

- **URL**: https://apify.com/dataspryva/naver-map-business-listings-with-menu-and-hours.md
- **Developed by:** [Dataspryva](https://apify.com/dataspryva) (community)
- **Categories:** Lead generation, Travel, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.49 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Naver Map Business Listings with Menu & Hours Data

Naver Map is where Koreans actually look up local businesses, and Korean listings carry detail Google rarely has: full weekly schedules with break times and last orders, itemized menus with prices and photos, booking and coupon programs, transit exits, and review breakdowns. This actor reads those public pages and turns them into structured records — by keyword, by map area, or from place links/IDs you already have. No Naver account, no API key, no cookies.

### What this actor does

- **Keyword search** — search any Korean keyword (e.g. `강남 맛집`, `부산 해운대 맛집`), with six Naver sort orders (relevance, popular, TV-featured, most reviewed, most saved, nearest).
- **Area sweep** — give a center (`37.4979,127.0276`) and a radius, and the actor sweeps a grid of map centers, deduplicating results. This is how you collect well past Naver's ~300-results-per-keyword ceiling.
- **Deep pagination** — beyond the first 100 results, the actor pages through Naver's own internal search endpoint, up to ~300–400 per keyword/center.
- **Direct place input** — paste desktop/mobile links, `naver.me` short links, `map.naver.com` entry links, or bare numeric place IDs. One extra lookup by the place's name recovers the search-listing fields (`businessCategory`, `commonAddress`, `dbType`, `categoryCodeList`) that the detail page does not carry.
- **Full menus** — every menu item Naver lists: name, integer KRW price + original text, description, photo(s), badges, set-menu flag, and its menu section.
- **Weekly hours** — per-day open/close, break windows, last order, next-day closing flags, upcoming irregular closures, regular days off, and a free-text note.
- **Filters** — category text, minimum review score/count, open now, booking, Naver Pay, coupon, takeout, newly opened, wheelchair entrance, and menu keyword. Server-side where Naver honors it, always re-checked client-side.
- **Visitor reviews (optional)** — real reviews as separate records: rating, text, visit date, voted keywords, photos, menu ordered, owner reply. Naver's review API is cursor-paginated (50 reviews per page) and has no hard cap, so `maxReviewsPerPlace` can go into the hundreds; if that API is ever unavailable the actor falls back to the ~20 reviews on the public review page.
- **Monitoring mode (optional)** — recurring jobs remember each place between runs and emit only new or changed places (`changeType` + `changedFields`), ignoring review-count and open/closed noise.
- **Empty fields are omitted** — a record only contains fields Naver actually returned for that place.

### Output per place

Business basics: `placeId`, `name`, `category`, `businessCategory`, `categoryCodeList`, `dbType`, `roadAddress`, `address`, `commonAddress`, `fullAddress`, `x`, `y`, `distance`, `distanceMeters`, `regionCode`, `placeUrl`, `sourceUrl` (URL mode), `searchKeyword`, `searchRank` (search mode).

Contact & links: `phone`, `virtualPhone`, `hasMobilePhoneNumber`, `talktalkUrl`, `chatBotUrl`, `routeUrl`, `homepageUrl`, `websites[]` (all published links with type + primary flag), `relatedLinks[]`.

Hours: `businessHoursStatus`, `businessHoursDescription`, `businessHoursEndsNextDay`, `businessHours[]` (day, start, end, `breakHours[]`, `lastOrderTime`, note, endsNextDay), `upcomingClosures[]`, `regularClosures`, `hoursFreeText`.

Menus: `menus[]` (name, `price` integer KRW, `priceText`, `currency`, `priceType`, description, `imageUrl`, `images[]`, `badges[]`, `recommend`, `isSetMenu`, `type`, `menuCategory`), `menuCategories[]`, `menuCount`, `menuUpdatedAt`, `menuImageUrls[]` (photos of the printed menu).

Reviews: `visitorReviewCount`, `visitorReviewScore`, `blogCafeReviewCount`, `totalReviewCount`, `saveCount`, `mediaReviewCount`, `reviewStats` (average, total, star distribution, image/author counts), `reviewImageCount`, `reviewAuthorCount`, `reviewThemes[]`, `reviewMenus[]`, `reviewKeywords[]`.

Amenities & programs: `conveniences[]`, `facilities[]`, `keywords[]`, `paymentInfo[]`, `parkingInfo`, `parking` (description/basic/valet), `petFriendly`, `noKidsZone`, `hasBooking`, `bookingUrl`, `bookingBusinessId`, `bookingReviewCount`, `bookingReviewScore`, `naverBookingCategory`, `hasNPay`, `hasCoupon`, `coupons[]`, `couponCount`, `naverOrder` (delivery/table-order/pre-order/pickup flags), `businessToolsUsing[]`, `promotionTitle`, `newOpening`, `hasWheelchairEntrance`, `michelinGuide` + `michelinGuideDetails` (year/star/comment/url/Bib flag), `broadcasts[]` + `tvAppearances[]` (program, channel, menu, date, episode).

Media & location extras: `imageUrl`, `imageUrls[]`, `imageCount`, `detailPhotos[]`, `visitorImages[]`, `totalImageCount`, `panoramaUrl`, `staticMapUrl`, `subwayStations[]`, `busStations[]`.

POS (where the business shares it): `posInsights`, `posSalesCount`, `posPopularDay`, `posAveragePrice`, `posPopularMenus[]`. Beauty listings may also carry `representativePrice`.

Every record ends with `recordType: "place"` and `scrapedAt`.

Review records (`recordType: "review"`): `placeId`, `sourceUrl`, `reviewId`, `content`, `rating`, `createdDate`, `visitedDate`, `visitCount`, `reviewerName`, `reviewerProfileUrl`, `reviewerReviewCount`, `votedKeywords[]`, `photos[]`, `menuItem`, `replyText`, `replyDate`, `originType`, `language`, `translatedText`, `scrapedAt`.

In monitoring mode every place record also carries `changeType` (`NEW`/`UPDATED`/`UNCHANGED`) and, for updates, `changedFields` (e.g. `["phone", "menus"]`).

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` or `byUrls` |
| `searchKeywords` | array | `["강남 맛집"]` | Keywords (mode=search). Region words narrow results. |
| `placeUrls` | array | – | Links or bare numeric place IDs (mode=byUrls) |
| `sortBy` | string | `relevance` | `relevance`, `popular`, `tv`, `reviews`, `saved`, `distance` |
| `searchCoordinates` | string | – | `"latitude,longitude"` map center |
| `searchRadiusKm` | int | – | With coordinates: area sweep radius (1–20 km) |
| `category` | string | – | Keep places whose category contains this text |
| `menuKeyword` | string | – | Keep places whose menus mention this text (needs details) |
| `maxResultsPerKeyword` | int | `20` | Cap per keyword (1–5000) |
| `includeDetails` | bool | `true` | Fetch each place's detail page (hours, menus, amenities, photos) |
| `includeReviews` | bool | `false` | Emit visitor reviews per place (cursor API, 50/request) |
| `maxReviewsPerPlace` | int | `10` | Review cap per place (1–3000; each 50 costs one request) |
| `minVisitorReviewScore` | number | – | Keep places at/above this score (0–5) |
| `minVisitorReviewCount` | int | – | Keep places with at least this many visitor reviews |
| `openNow` | bool | `false` | Only places currently open |
| `hasBooking` | bool | `false` | Only places with Naver booking |
| `hasNpay` | bool | `false` | Only places accepting Naver Pay |
| `hasCoupon` | bool | `false` | Only places with an active coupon |
| `takeout` | bool | `false` | Only places offering takeout (포장) |
| `newlyOpened` | bool | `false` | Only newly opened places |
| `wheelchairAccessible` | bool | `false` | Only places with a wheelchair-accessible entrance |
| `maxItems` | int | `100` | Cap on place records (reviews are extra) |
| `monitoringMode` | bool | `false` | Emit only new/changed places vs the previous run |
| `monitoringStateKey` | string | – | Optional name for the monitoring memory |
| `emitUnchanged` | bool | `false` | Also emit `changeType: "UNCHANGED"` places |

#### Example: neighborhood restaurants with full menus

```json
{
  "mode": "search",
  "searchKeywords": ["이태원 맛집"],
  "maxResultsPerKeyword": 30,
  "category": "한식",
  "minVisitorReviewScore": 4.3,
  "includeDetails": true
}
```

#### Example: every cafe within 2 km of Gangnam Station

```json
{
  "mode": "search",
  "searchKeywords": ["카페"],
  "searchCoordinates": "37.4979,127.0276",
  "searchRadiusKm": 2,
  "maxResultsPerKeyword": 800,
  "includeDetails": false,
  "maxItems": 800
}
```

#### Example: menu monitoring — who serves pizza in Gangnam

```json
{
  "mode": "search",
  "searchKeywords": ["강남 맛집"],
  "maxResultsPerKeyword": 100,
  "menuKeyword": "피자",
  "includeDetails": true
}
```

#### Example: daily monitoring — only new or changed places

```json
{
  "mode": "search",
  "searchKeywords": ["성수 카페"],
  "maxResultsPerKeyword": 100,
  "monitoringMode": true,
  "monitoringStateKey": "seongsu-cafes"
}
```

#### Example: known places with reviews

```json
{
  "mode": "byUrls",
  "placeUrls": [
    "https://pcmap.place.naver.com/restaurant/2020647783/home",
    "https://naver.me/FqW0LLx9",
    "1254234366"
  ],
  "includeReviews": true,
  "maxReviewsPerPlace": 20
}
```

### Use cases

- **Restaurant & retail intelligence** — menus with prices, hours with breaks, and amenities across a district, ready for comparison dashboards.
- **Local SEO & listing audits** — check hours, phone, menus, and review scores for client locations and competitors.
- **Lead generation** — filter by booking, Naver Pay, coupon, or takeout to build outreach lists for specific business types.
- **Delivery/ordering analysis** — POS popularity, review menus, and order-program flags show what actually sells.
- **Travel & guides** — build Korean neighborhood guides with real hours, prices, and transit exits.

### FAQ

**Do I need a Naver account or API key?**
No. The actor reads the same public pages a browser loads — no login, cookies, or key.

**Why do some places have no `menus`?**
Naver only serves menu data for businesses that published one. A clinic or convenience store may have none; the field is simply omitted.

**How many results can one keyword return?**
Naver's own search exposes up to 100 results on the first page and up to ~300–400 through deeper pages per map center. To collect more, add `searchCoordinates` + `searchRadiusKm` (area sweep) or use narrower keywords.

**How does `sortBy: "distance"` work?**
It needs `searchCoordinates`; Naver then orders results nearest-first from that point.

**How many reviews does `includeReviews` return?**
As many as you ask for, up to the place's total: the actor pages Naver's review API with the same cursor the website uses (50 reviews per page, no hard cap observed). If that API is ever blocked, it falls back to the ~20 reviews embedded on the public review page and says so in the log.

**Are prices numbers or text?**
Both: `price` is an integer KRW amount when Naver publishes a fixed price, and `priceText` keeps Naver's original string (useful for "시가"/market price, which has no number).

**How does monitoring mode work?**
Turn on `monitoringMode` and (optionally) name the memory with `monitoringStateKey`. The actor stores a per-place fingerprint in its key-value store and, on later runs with the same key/inputs, emits only `NEW` or `UPDATED` places, listing what changed. Review counts, review scores and current open/closed status are ignored so runs aren't billed for noise. The search itself still runs in full — you pay for the scrape, not per change.

**Is a proxy required?**
No. Direct requests work; if Naver starts rate-limiting, the actor automatically retries through an Apify proxy.

**Is this affiliated with Naver?**
No. This is an independent third-party actor reading public Naver Map pages. It is not affiliated with or endorsed by Naver Corporation.

### Scope / Limitations

- **~300–400 results per keyword per map center** is Naver's own search ceiling; the area sweep multiplies it per center.
- **Review depth follows Naver's own cursor API** (50 reviews per page). If Naver ever blocks it, the actor falls back to ~20 reviews per place from the public review page and logs a warning.
- **Monitoring mode compares stable fields only** (name, category, address, phone, homepage, weekly hours, menus, amenities). Review counts/scores and live open status are deliberately ignored; pass `emitUnchanged` to also emit unchanged places.
- **Hours are taken from the first published schedule** — 0/44 probed places carried multiple schedule variants.
- **English translations are not available** — Naver's English name/category/address are not served on any cookieless page; Korean values are kept verbatim.
- **`includeDetails=false` (fast mode)** returns search-level fields only (name, category, address, coordinates, review counts, hours status, coupons, flags) — menus, full hours, and amenities need details.
- **Some fields are vertical-specific** — POS insights, menus, or representative prices appear only where Naver publishes them for that business type.
- **`saveCount`** (how many users bookmarked the place) is only served by Naver's category/region listing pages; in URL mode it is omitted. Other search-listing fields (`businessCategory`, `commonAddress`, `dbType`, `categoryCodeList`) are recovered in URL mode with one extra name lookup.
- **English name/category/address are not available** — Naver does not serve them on any cookieless page (verified against `lang=en`/`locale=en` variants and the internal APIs), so Korean values are kept verbatim.

# Actor input Schema

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

What to fetch. `search` discovers places by keyword; `byUrls` fetches places you already know (URLs or place IDs).

## `searchKeywords` (type: `array`):

Keywords to search on Naver Map, e.g. `강남 맛집` (Gangnam restaurants) or `이태원 카페` (Itaewon cafes). Include a region name for local results. Naver returns up to 100 places per keyword from the first page and up to ~300 via deeper pages; add a map area (Search coordinates + Radius) or narrower keywords for more.

## `placeUrls` (type: `array`):

Naver Map places to fetch directly. Accepts full links (pcmap.place.naver.com, m.place.naver.com, map.naver.com/p/entry/place/...), `naver.me` short links, and bare numeric place IDs.

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

How Naver orders search results. `distance` sorting needs Search coordinates.

## `searchCoordinates` (type: `string`):

Map center as `latitude,longitude`, e.g. `37.4979,127.0276` for Gangnam Station. Used to rank results around a point, for distance sorting, and as the center of an area sweep.

## `searchRadiusKm` (type: `integer`):

When set together with Search coordinates, the actor sweeps the whole circle (grid of map centers) instead of one center — this is how to collect more than Naver's ~300-per-keyword limit. Needs a broad keyword (e.g. `맛집`).

## `category` (type: `string`):

Only keep places whose category contains this text (e.g. `한식`, `카페`, `Cafe`). Leave blank for all categories.

## `menuKeyword` (type: `string`):

Only keep places whose menu names or descriptions contain this text (e.g. `피자`). Requires Include place details to be on. Leave blank for all menus.

## `maxResultsPerKeyword` (type: `integer`):

Cap on places emitted per keyword (before filters). First page gives up to 100 places; deeper Naver pages add up to ~300 total per map center, and an area sweep multiplies that per center.

## `includeDetails` (type: `boolean`):

Fetch each place's detail page for full weekly hours (breaks, last order, upcoming closures), full menus with prices, facilities, parking, photos, review breakdown and more. Slower but much richer data.

## `includeReviews` (type: `boolean`):

Emit real visitor reviews per place as separate `recordType: "review"` records (rating, text, dates, keywords, photos, owner replies). Uses Naver's cursor-paginated review API (50 per request) up to Max reviews per place; falls back to the ~20 reviews embedded on the public review page if that API is unavailable. Works in both modes.

## `maxReviewsPerPlace` (type: `integer`):

Cap on review records emitted per place when Include visitor reviews is on. Naver serves 50 reviews per request and does not expose a hard cap, so this can go high (e.g. 500); each 50 reviews costs one extra request.

## `minVisitorReviewScore` (type: `number`):

Only keep places with a visitor review score at or above this value (0-5). Leave blank for no filter.

## `minVisitorReviewCount` (type: `integer`):

Only keep places with at least this many visitor reviews. Leave blank for no filter.

## `openNow` (type: `boolean`):

Only keep places currently marked as open by Naver Map.

## `hasBooking` (type: `boolean`):

Only keep places that support online booking/reservations through Naver.

## `hasNpay` (type: `boolean`):

Only keep places that accept Naver Pay.

## `hasCoupon` (type: `boolean`):

Only keep places with an active coupon or promotion.

## `takeout` (type: `boolean`):

Only keep places marked as offering takeout (포장).

## `newlyOpened` (type: `boolean`):

Only keep places Naver marks as newly opened.

## `wheelchairAccessible` (type: `boolean`):

Only keep places with a wheelchair-accessible entrance.

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

Hard cap on total emitted place records across all keywords/URLs (review records are extra).

## `monitoringMode` (type: `boolean`):

Recurring-job mode: remembers each place between runs (in the Actor's key-value store) and emits only places that are new or whose name, category, address, phone, homepage, weekly hours, menus, or amenities changed. Adds `changeType` (NEW/UPDATED/UNCHANGED) and `changedFields` to each emitted place. Review counts and current open/closed status are ignored so runs are not billed for noise.

## `monitoringStateKey` (type: `string`):

Optional name for the monitoring state (mode=monitoringMode). Leave blank to derive the key from the run inputs, so the same keywords/URLs always compare against the same memory.

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

In Monitoring mode, also emit places with `changeType: "UNCHANGED"` instead of skipping them.

## Actor input object example

```json
{
  "mode": "search",
  "searchKeywords": [
    "강남 맛집"
  ],
  "placeUrls": [],
  "sortBy": "relevance",
  "maxResultsPerKeyword": 20,
  "includeDetails": true,
  "includeReviews": false,
  "maxReviewsPerPlace": 10,
  "openNow": false,
  "hasBooking": false,
  "hasNpay": false,
  "hasCoupon": false,
  "takeout": false,
  "newlyOpened": false,
  "wheelchairAccessible": false,
  "maxItems": 100,
  "monitoringMode": false,
  "emitUnchanged": false
}
```

# Actor output Schema

## `places` (type: `string`):

Dataset containing all scraped Naver Map places and (optionally) their visitor reviews.

# 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",
    "searchKeywords": [
        "강남 맛집"
    ],
    "placeUrls": [],
    "sortBy": "relevance",
    "maxResultsPerKeyword": 20,
    "includeDetails": true,
    "includeReviews": false,
    "maxReviewsPerPlace": 10,
    "openNow": false,
    "hasBooking": false,
    "hasNpay": false,
    "hasCoupon": false,
    "takeout": false,
    "newlyOpened": false,
    "wheelchairAccessible": false,
    "maxItems": 100,
    "monitoringMode": false,
    "emitUnchanged": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataspryva/naver-map-business-listings-with-menu-and-hours").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",
    "searchKeywords": ["강남 맛집"],
    "placeUrls": [],
    "sortBy": "relevance",
    "maxResultsPerKeyword": 20,
    "includeDetails": True,
    "includeReviews": False,
    "maxReviewsPerPlace": 10,
    "openNow": False,
    "hasBooking": False,
    "hasNpay": False,
    "hasCoupon": False,
    "takeout": False,
    "newlyOpened": False,
    "wheelchairAccessible": False,
    "maxItems": 100,
    "monitoringMode": False,
    "emitUnchanged": False,
}

# Run the Actor and wait for it to finish
run = client.actor("dataspryva/naver-map-business-listings-with-menu-and-hours").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": "search",
  "searchKeywords": [
    "강남 맛집"
  ],
  "placeUrls": [],
  "sortBy": "relevance",
  "maxResultsPerKeyword": 20,
  "includeDetails": true,
  "includeReviews": false,
  "maxReviewsPerPlace": 10,
  "openNow": false,
  "hasBooking": false,
  "hasNpay": false,
  "hasCoupon": false,
  "takeout": false,
  "newlyOpened": false,
  "wheelchairAccessible": false,
  "maxItems": 100,
  "monitoringMode": false,
  "emitUnchanged": false
}' |
apify call dataspryva/naver-map-business-listings-with-menu-and-hours --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataspryva/naver-map-business-listings-with-menu-and-hours"
        }
    }
}
```

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/l8lB2zLDoXJ2xjpAe/builds/C7P2a9cthLY2sPU9H/openapi.json
