# Naver Map Scraper (`huggable_quote/naver-map-scraper`) Actor

Scrape places, menus, business hours, reviews and more from Naver Map (map.naver.com). Supports keyword search and direct URL input.

- **URL**: https://apify.com/huggable\_quote/naver-map-scraper.md
- **Developed by:** [OrbitData Labs](https://apify.com/huggable_quote) (community)
- **Categories:** E-commerce, SEO tools, Travel
- **Stats:** 267 total users, 38 monthly users, 100.0% runs succeeded, 5 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $3.00 / 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.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Naver Map Scraper

Extract rich, structured data from [Naver Map](https://map.naver.com) — Korea's dominant local search platform. Collect place details, menus, business hours, reviews, and more through keyword search or direct URL input.

### Features

- **Keyword Search** — Search terms like "강남 맛집" or "홍대 카페" and scrape all matching places.
- **Direct URL Input** — Provide specific Naver Map place URLs to scrape individual businesses. Supports full URLs and short URLs (`naver.me` links).
- **Rich Place Details** — Name, category, address, coordinates, phone, virtual phone, homepage, website URL, business hours, facilities, conveniences, parking info, images, subway stations, and more.
- **Full Menu Data** — Menu items with names, prices, descriptions, images, and recommendation flags.
- **Review Collection** — Visitor reviews (rating, body, author, tags, media) and blog reviews (title, content, URL, thumbnail).
- **Review Filtering** — Set a cutoff date to only collect recent reviews.
- **Proxy Support** — Built-in Apify proxy support to avoid rate limiting (HTTP 429).
- **Anti-blocking** — Uses TLS fingerprinting (Chrome impersonation) for reliable access.

### How It Works

1. **Search Phase** — For each keyword, the Actor searches Naver Map and collects place IDs (up to `maxResultsPerKeyword` per keyword). For direct URLs, place IDs are extracted automatically.
2. **Detail Phase** — For each place ID, the Actor fetches the detail page and parses the `__APOLLO_STATE__` for structured data.
3. **Review Phase** (optional) — If `includeReviews` is enabled, visitor reviews and blog reviews are collected via Naver's GraphQL API with pagination.

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchKeywords` | `string[]` | — | Search terms (e.g. `["강남 맛집", "홍대 카페"]`) |
| `urls` | `string[]` | — | Naver Map place URLs (full or short `naver.me` links) |
| `maxResultsPerKeyword` | `integer` | `100` | Max places to collect per keyword (1–10,000) |
| `includeDetails` | `boolean` | `true` | When `true`, fetches each place's detail page (menus, hours, facilities, images, description). When `false` (**fast mode**), skips it and returns search-level data only (name, category, phone, virtual phone, address, coordinates, review counts) — ~2× faster and cheaper. No effect on direct URL inputs. |
| `includeReviews` | `boolean` | `false` | Whether to collect visitor and blog reviews |
| `maxReviewPages` | `integer` | `50` | Max review pages per place. Visitor: 50 reviews/page (no server limit). Blog: 10 reviews/page (server cap ~100/place). |
| `reviewCutoffDate` | `string` | `"2024-01-01"` | Only collect reviews on or after this date (YYYY-MM-DD) |
| `proxyConfiguration` | `object` | — | Apify proxy settings (recommended) |

You must provide at least one of `searchKeywords` or `urls`.

#### Supported URL Formats

- Full place URL: `https://map.naver.com/p/entry/place/1976543477`
- Search result URL: `https://map.naver.com/p/search/강남맛집/place/1234567890`
- Short URL: `https://naver.me/FqW0LLx9` (automatically resolved via redirect)
- Mobile URL: `https://m.place.naver.com/place/1234567890`

#### Example Input

**Search by keyword:**

```json
{
    "searchKeywords": ["강남 맛집"],
    "maxResultsPerKeyword": 50,
    "includeReviews": true,
    "maxReviewPages": 10,
    "reviewCutoffDate": "2025-01-01",
    "proxyConfiguration": {
        "useApifyProxy": true
    }
}
```

**Scrape a single place by URL:**

```json
{
    "urls": ["https://naver.me/FqW0LLx9"],
    "includeReviews": true,
    "maxReviewPages": 5
}
```

### Output Example

Each dataset item contains full place details:

```json
{
    "place_id": "1887323843",
    "name": "더 플라자 도원",
    "category": "중식당",
    "categoryCode": "restaurant",
    "address": "서울 중구 소공로 119",
    "roadAddress": "서울 중구 소공로 119 더 플라자 3층",
    "phone": "02-310-7300",
    "virtualPhone": "0507-1234-5678",
    "homepage": "https://www.hoteltheplaza.com/kr/dining/taoyuen.jsp",
    "siteUrl": "https://booking.naver.com/...",
    "x": "126.9784",
    "y": "37.5660",
    "businessHours": [
        {
            "name": "영업시간",
            "status": "영업 중",
            "description": "21:30에 영업 종료",
            "schedule": [
                { "day": "매일", "start": "11:30", "end": "21:30" }
            ]
        }
    ],
    "conveniences": ["예약", "단체 이용 가능", "주차", "발렛파킹"],
    "facilities": ["예약", "주차", "발렛파킹", "무선 인터넷"],
    "hasMobilePhoneNumber": false,
    "visitorReviewsTotal": 724,
    "visitorReviewsScore": 4.52,
    "reviewStats": {
        "avgRating": 4.52,
        "totalCount": 724,
        "imageReviewCount": 512,
        "authorCount": 680
    },
    "reviewThemes": [
        { "code": "TASTE", "label": "맛", "count": 450 }
    ],
    "reviewMenus": [
        { "label": "북경오리", "count": 120 }
    ],
    "menus": [
        {
            "name": "도원 오마카세",
            "price": "350000",
            "description": "",
            "images": ["https://ldb-phinf.pstatic.net/..."],
            "recommend": true
        }
    ],
    "images": [
        "https://ldb-phinf.pstatic.net/..."
    ],
    "subwayStations": [
        { "name": "시청역", "typeDesc": "6번 출구에서 87m" }
    ],
    "description": "서울의 가장 명망 있는 전통 중식 레스토랑 도원이..."
}
```

When `includeReviews` is enabled, each item also includes:

```json
{
    "visitorReviews": [
        {
            "review_id": "abc123",
            "rating": 5,
            "body": "음식이 정말 맛있었습니다...",
            "author_nickname": "홍길동",
            "visited": "2025-02-15",
            "created": "2025-02-20",
            "tags": ["맛있어요", "분위기좋아요"],
            "voted_keywords": ["맛", "서비스"],
            "media_count": 3
        }
    ],
    "blogReviews": [
        {
            "title": "강남 맛집 추천 후기",
            "contents": "지난 주말에 방문했는데...",
            "author_name": "맛집블로거",
            "url": "https://blog.naver.com/...",
            "date": "2025-03-01"
        }
    ]
}
```

### Use Cases

- **Market Analysis** — Compare businesses by ratings, review counts, and pricing across locations.
- **Competitor Research** — Track competitors' menus, pricing changes, and customer feedback over time.
- **Local SEO Research** — Analyze category rankings and review patterns for specific keywords.
- **Restaurant & Retail Intelligence** — Gather menu items, pricing, business hours, and facility data at scale.
- **Review Monitoring** — Collect and filter reviews by date for ongoing sentiment tracking.

### Pricing

This Actor uses the **Pay-Per-Event** model — you only pay for what you scrape, with no monthly subscription.

| Event | Price | Per 1,000 | Description |
|-------|-------|-----------|-------------|
| Place scraped | $0.003 | **$3.00** | Per place in the dataset |
| Review page | $0.001 | $1.00 | Per review page fetched (20 reviews/page). Only charged when `includeReviews` is enabled. |

**Cost examples:**

- 100 places (no reviews) = ~**$0.30**
- 1,000 places (no reviews) = ~**$3.00**
- 100 places + reviews (avg 5 pages each) = ~**$0.80**
- 1,000 places + reviews (avg 5 pages each) = ~**$8.00**

No hidden fees. Platform usage costs are included in the event prices. Free-tier users get $5/month of Apify platform credit — enough for ~1,600 places.

### Review Collection Limits

| Review Type | Page Size | Server Limit | Notes |
|---|---|---|---|
| **Visitor reviews** | 50 reviews/page | **No limit** | Cursor-based pagination. All reviews can be collected by increasing `maxReviewPages`. |
| **Blog reviews** | 10 reviews/page | **~100 per place** | Naver imposes a `maxItemCount` cap (~100–113) per place. The actor collects up to ~90% of this limit. |

**Example:** For a place with 3,000 visitor reviews and 400 blog reviews:

- `maxReviewPages=3` → 150 visitor reviews + ~30 blog reviews
- `maxReviewPages=10` → 500 visitor reviews + ~90 blog reviews
- `maxReviewPages=60` → all 3,000 visitor reviews + ~90 blog reviews (blog reviews hit server cap)

### Tips for Best Results

- **Use proxy** — Enable Apify proxy to avoid HTTP 429 rate limiting from Naver.
- **Start small** — Test with a low `maxResultsPerKeyword` value first to verify output before scaling up.
- **Review filtering** — Set `reviewCutoffDate` to a recent date to reduce scraping time and collect only relevant reviews.
- **Spending limit** — Set a maximum cost per run in the Apify Console to control your budget. The Actor will stop gracefully when the limit is reached.

### Changelog

#### v1.9 (2026-06)

- **Added fast mode (`includeDetails`)**: Set `includeDetails=false` to skip the per-place detail page fetch and return search-level data only (name, category, phone, virtual phone, address, coordinates, review counts). Roughly halves run time and cost — ideal for bulk contact/address lookups. Results are tagged `basicInfoOnly: true`.
- **Further cost optimization**: Lowered run memory to 256 MB after telemetry showed real usage never exceeds ~85 MB even on large runs. Halves compute cost with no impact on speed or reliability.
- **Use Apify's synthetic `apify-actor-start` event** for run-start billing (auto-charged by the platform, first 5 s of compute free) instead of a manually-charged start event.

#### v1.8 (2026-06)

- **Fixed medical/category search returning 0 results**: Naver serves some categories (e.g. dermatology/hospitals via the `hospitals` key) under root keys the parser didn't recognize. Search now auto-detects any place-list key, so medical, dental, vet, fitness, beauty, etc. searches work.

#### v1.7 (2026-06)

- **Added `hasMobilePhoneNumber`**: Distinguishes places with no phone from places whose number exists but Naver withholds it from the page (in that case `phone`/`virtualPhone` may both be null).

#### v1.6 (2026-06)

- **Cost optimization**: Reduced run memory (1024→512 MB) and shortened inter-request delays, cutting platform usage cost substantially while keeping success rate. Retry/backoff on HTTP 429 unchanged.

#### v1.5 (2026-05)

- **Fixed search**: Adapted to Naver's new `placeList` API structure (previously `restaurantList`/`places`)
- **Fixed blog review count**: `blogReviewTotal` was always 0 due to parameterized key mismatch
- **Improved blog review collection**: Changed page size from 20 to 10, collecting ~90% of server cap (up from ~80%)
- Added `keywords` as an alias for `searchKeywords` for flexibility
- Added warnings for unrecognized input fields
- Documented review collection limits in README

#### v1.4 (2026-04)

- **Added per-place billing**: Every place scraped now triggers a `place-scraped` charge event ($0.003/place)
- Graceful stop when charge limit is reached with user-friendly status message
- Review collection automatically disabled when review charge limit is hit
- Input descriptions now show per-event pricing for transparency

#### v1.3 (2026-04)

- Added virtualPhone, homepage, siteUrl, conveniences to output table views
- Added missing fields (homepageEtc, siteLanding, categoryCodeList) to dataset schema
- Updated README output example with full contact/website fields

#### v1.2 (2026-04)

- Added output schema for structured table view in Apify Console
- Fixed proxy configuration to correctly use Apify proxy credentials
- Improved error handling — individual place failures no longer crash the entire run
- Reduced retry aggressiveness (3 retries, capped backoff) for faster completion
- Success rate improved to 100%

#### v1.1 (2026-04)

- Proxy password resolution via `APIFY_PROXY_PASSWORD` environment variable
- Exception handling for all scraping stages (search, detail, reviews, charging)
- Graceful budget limit enforcement

#### v1.0 (2026-03)

- Initial release
- Keyword search and direct URL input
- Full place detail extraction
- Visitor and blog review collection with date filtering
- Pay-Per-Event pricing with review page charging

# Actor input Schema

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

List of search keywords (e.g. '강남 맛집', '홍대 카페'). The Actor will search Naver Map for each keyword and scrape place details from the results.

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

List of Naver Map place URLs. Supports full URLs (e.g. https://map.naver.com/p/entry/place/1234567890) and short URLs (e.g. https://naver.me/FqW0LLx9). The place ID is automatically extracted.

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

Maximum number of places to collect per search keyword. Each place costs $0.003.

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

When enabled (default), each place's detail page is fetched to collect full data: menus, business hours, facilities, description, images, etc.

When **disabled (fast mode)**, the detail page fetch is skipped and only the data already available from search results is returned: name, category, phone, virtual phone, address, road address, coordinates, and review counts. This roughly halves the run time and lowers cost — ideal when you only need contact/address info. (Has no effect on direct URL inputs, which always fetch the detail page.)

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

When enabled, visitor reviews and blog reviews are collected for each place (additional $0.001 per review page). When disabled, only place details are scraped.

**Visitor reviews**: No server-side limit. Controlled entirely by maxReviewPages (50 reviews/page). Set maxReviewPages high enough to collect all reviews.

**Blog reviews**: Naver imposes a server-side cap of ~100 per place (maxItemCount). The actor collects up to ~90% of this limit regardless of maxReviewPages.

## `maxReviewPages` (type: `integer`):

Maximum number of review pages to fetch per place. Visitor reviews use cursor-based pagination (50 reviews/page, no server limit). Blog reviews use offset pagination (10 reviews/page, server-side cap of ~100 per place). Example: maxReviewPages=3 → up to 150 visitor reviews + up to ~90 blog reviews.

## `reviewCutoffDate` (type: `string`):

Only collect reviews on or after this date (YYYY-MM-DD format).

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

Apify proxy settings. Proxy is enabled by default to avoid HTTP 429 rate limiting from Naver.

## Actor input object example

```json
{
  "searchKeywords": [
    "강남 맛집"
  ],
  "maxResultsPerKeyword": 5,
  "includeDetails": true,
  "includeReviews": false,
  "maxReviewPages": 50,
  "reviewCutoffDate": "2024-01-01",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "searchKeywords": [
        "강남 맛집"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("huggable_quote/naver-map-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 = { "searchKeywords": ["강남 맛집"] }

# Run the Actor and wait for it to finish
run = client.actor("huggable_quote/naver-map-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 '{
  "searchKeywords": [
    "강남 맛집"
  ]
}' |
apify call huggable_quote/naver-map-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,huggable_quote/naver-map-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/SjaMAqRmjKPocwo9T/builds/fAkOtc4FN6B5mPUqe/openapi.json
