Naver Place Multi-Location Review Monitor avatar

Naver Place Multi-Location Review Monitor

Pricing

from $2.00 / 1,000 location checks

Go to Apify Store
Naver Place Multi-Location Review Monitor

Naver Place Multi-Location Review Monitor

Enter Naver Place locations (ID + your label) and get change rows - new reviews, owner replies added or edited - plus one free summary row per location: unanswered reviews, oldest unanswered age, reply rate, rating, top keywords. For franchises and agencies. No reviewer personal data.

Pricing

from $2.00 / 1,000 location checks

Rating

0.0

(0)

Developer

SUNGHWAN CHO

SUNGHWAN CHO

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

8 hours ago

Last modified

Categories

Share

Enter a list of Naver Place locations (place ID + your own label and group) and get, on every run, what changed since the last run — new reviews, owner replies added, owner replies edited — plus one status row per location: how many reviews are still unanswered, how old the oldest unanswered review is, reply rate, average rating and top keywords. Built for franchise head offices and agencies that manage many stores on Naver Map (Naver Place), South Korea's main map and local review service. Reviewer identity is never collected.

No login, no API key and no browser needed.

Which Actor do I need?

Multi-Location Review Monitor (this Actor)Naver Place Reviews Scraper
PurposeA recurring status report across many locations: what changed and what is still unansweredA raw review export: every review of a place as a row
Typical userFranchise HQ, multi-store brand, marketing or operations agencyAnalyst, researcher, data pipeline, LLM input
InputLocations with your label and group tagsPlace IDs or URLs
Rows you getOnly changes (newReview, ownerReplyAdded, ownerReplyChanged) + one summary row per locationAll reviews up to your limit (photos, visit context, reactions, verification type)
Owner repliesDetects replies added or edited after the review was first seenReply text as it is at scrape time
Unanswered backlogCount, oldest age in days and reply rate per locationNot calculated
Scheduled run with nothing newLocation summary rows with the current unanswered statusPlace summary rows only

Use this Actor for a daily or weekly check of your stores. Use the Reviews Scraper when you need the full review history or fields such as photos. Need place IDs first? Naver Place Search Scraper returns them in its id field.

What you get

Every row has a type field.

Change rows ("type": "change") — one per detected change, with the full review:

  • eventType: newReview (a review not seen in earlier runs), ownerReplyAdded (a known review got its first owner reply) or ownerReplyChanged (the reply text was edited)
  • Your label and group, placeId, placeName
  • rating, review text, visitedAt, createdAt (when the review was written), keyword tags in Korean and as English codes, menuItem
  • hasOwnerReply, ownerReply, ownerReplyDateLabel
  • needsAttention: true when the star rating is 2 or lower, or the text contains one of these Korean complaint terms: 불친절, 불만, 실망, 불결, 불쾌, 최악, 환불, 위생…문제. A simple, fixed rule — not an AI judgment
  • E-mail addresses and phone numbers written inside the review or the reply are replaced with [email] / [phone]

Location summary rows ("type": "locationSummary", free) — one per location on every run, also when nothing changed:

  • status and stopReason, so a blocked or failed location is never mistaken for "no new reviews"
  • newReviewCount, ownerReplyAddedCount, ownerReplyChangedCount since previousCheckedAt, and avgRatingOfNewReviews
  • unansweredCountInSample, oldestUnansweredDaysInSample (+ the review ID and visit date), replyRateInSample, needsAttentionUnansweredCountInSample
  • reviewsInSample, avgRatingInSample, lowRatingCountInSample, topKeywordsInSample (top 5 keyword tags)
  • placeAvgRating, placeTotalReviewCount (Naver's headline numbers for the whole place)

Fields ending in InSample are calculated over the reviews read in this run — reviews visited within the observation window (windowDays, default 30), up to maxReviewsPerLocation. They are not statistics of the place's whole history.

One run summary row ("type": "runSummary", free): locations by status, total change rows, total unanswered reviews, requests sent and retried. The same report with a per-location list is saved in the run's key-value store as RUN_SUMMARY.

Missing values are null; keys are never left out. Numbers are numbers.

Not collected: reviewer nicknames, profile pictures, profile links, user IDs and receipt links are never requested from Naver.

Use cases

  • Agency reporting — one scheduled run for all client stores; group rows by group (client) and label (store) for the weekly report
  • Reply follow-up — list locations where unansweredCountInSample is above 0 or oldestUnansweredDaysInSample is over your target, and check that replies were actually posted (ownerReplyAdded)
  • Reply audit — ownerReplyChanged shows when a store edited a reply after you first saw it
  • Alerts — send change rows with needsAttention: true to Slack, e-mail or a sheet through Apify integrations
  • AI agents — a short list in, flat rows out; RUN_SUMMARY gives the result without reading the log

Input

FieldDescription
locationsRequired. List of objects: placeId (Naver Place ID or Naver Map place URL), optional label and group (your own text, copied to every row). A plain ID or URL string also works.
windowDaysObservation window in days, by visit date. Default 30. Changes are detected and summary numbers are calculated for reviews inside this window.
maxReviewsPerLocationUpper limit of reviews read per location inside the window. Default 200, maximum 500.
emitExistingOnFirstRunDefault false. The first run for a location only sets the starting point (summary row, no change rows). Set true to also receive the reviews currently in the window as newReview rows with isBaseline: true.
historyStoreNameKey-value store that remembers what was already reported. Default multi-location-review-monitor-history. Use one name per client or schedule.
proxyConfigurationKeep the default Apify Proxy.
{
"locations": [
{ "placeId": "1922651675", "label": "Seongsu store", "group": "Client A" },
{ "placeId": "https://map.naver.com/p/entry/place/1559904682", "label": "Seoul Forest store", "group": "Client A" }
],
"windowDays": 30
}

Output

A change row from a test run:

{
"type": "change",
"eventType": "newReview",
"source": "naver",
"schemaVersion": 1,
"placeId": "1922651675",
"label": "Demo store 1",
"group": "Demo client",
"placeName": "노틀던",
"reviewId": "6abf33448f9dd532461b9928",
"rating": 5,
"text": "디저트도 예쁘고 맛있어요!! 다른메뉴도 먹으러 또오고싶어요",
"visitedAt": "2026-10-02T04:23:12.000Z",
"createdAt": "2026-10-02T04:29:56.000Z",
"visitedLabel": "10.2.금",
"createdLabel": "10.2.금",
"keywords": ["커피가 맛있어요", "디저트가 맛있어요", "아늑해요", "음악이 좋아요"],
"keywordCodes": ["coffee_good", "dessert_good", "cozy", "music_good"],
"menuItem": "노틀던 누아",
"hasOwnerReply": false,
"ownerReply": null,
"ownerReplyDateLabel": null,
"needsAttention": false,
"isBaseline": false,
"previousCheckedAt": "2026-09-30T00:00:00.000Z",
"url": "https://map.naver.com/p/entry/place/1922651675?placePath=/review",
"scrapedAt": "2026-10-02T06:45:24.139Z"
}

A location summary row from a first run with "windowDays": 14:

{
"type": "locationSummary",
"source": "naver",
"schemaVersion": 1,
"placeId": "1922651675",
"label": "Demo store 1",
"group": "Demo client",
"placeName": "노틀던",
"status": "completed",
"stopReason": "windowCovered",
"errorMessage": null,
"isFirstCheck": true,
"previousCheckedAt": null,
"windowDays": 14,
"windowStart": "2026-09-18T06:45:03.688Z",
"windowFullyScanned": true,
"newReviewCount": null,
"ownerReplyAddedCount": null,
"ownerReplyChangedCount": null,
"changeRowsSaved": 0,
"avgRatingOfNewReviews": null,
"reviewsInSample": 34,
"ratedReviewsInSample": 34,
"avgRatingInSample": 5,
"lowRatingCountInSample": 0,
"repliedCountInSample": 0,
"unansweredCountInSample": 34,
"replyRateInSample": 0,
"oldestUnansweredDaysInSample": 13,
"oldestUnansweredReviewId": "6aacf2418c8d40a9626925ac",
"oldestUnansweredVisitedAt": "2026-09-18T08:05:40.000Z",
"needsAttentionUnansweredCountInSample": 0,
"topKeywordsInSample": [
{ "code": "dessert_good", "keyword": "디저트가 맛있어요", "count": 31 },
{ "code": "special_menu", "keyword": "특별한 메뉴가 있어요", "count": 20 },
{ "code": "coffee_good", "keyword": "커피가 맛있어요", "count": 19 },
{ "code": "drink_good", "keyword": "음료가 맛있어요", "count": 12 },
{ "code": "kind", "keyword": "친절해요", "count": 10 }
],
"placeAvgRating": 4.97,
"placeTotalReviewCount": 1160,
"pagesFetched": 1,
"locationCheckCharged": false,
"input": null,
"url": "https://map.naver.com/p/entry/place/1922651675?placePath=/review",
"scrapedAt": "2026-10-02T06:45:04.152Z"
}

Export the dataset as JSON, CSV or Excel, or read it through the Apify API. Filter by type to separate changes from summaries.

How change detection works

  1. First run for a location reads the observation window and stores a fingerprint of each review's owner reply in the key-value store historyStoreName in your Apify account. It returns the summary row only (isFirstCheck: true, change counts null), unless emitExistingOnFirstRun is on.
  2. Later runs read the window again and compare:
    • a review that is not in history → newReview. Naver lists reviews by visit date, and people often write days after the visit; such late reviews are found as long as the visit is inside the window. A review that is not in history but was written before the previous check (it was outside that run's scan) is recorded silently and not reported as new.
    • a known review that now has a reply and had none → ownerReplyAdded
    • a known review whose reply text differs (ignoring whitespace) → ownerReplyChanged
  3. Only change rows that were actually stored are recorded in history. Rows cut off by your max cost per run, or lost to an error, are reported again on the next run.

Status values

statusMeaning
completedThe window was read and all changes were stored. stopReason is windowCovered, endOfList or maxReviewsReached (window larger than maxReviewsPerLocation; see windowFullyScanned).
partialA later page failed after retries. Changes found so far are reported; the location check is not charged.
budgetLimitedYour max cost per run was reached at this location.
notStartedNot requested and not charged (costLimitReached or runTimeoutApproaching).
failedblocked (Naver kept answering HTTP 429/403), requestFailed, placeNotFound, invalidInput or datasetWriteFailed. Counts are null, not 0. Not charged.

If every location fails, the run itself fails. Otherwise the run succeeds and the rows tell you what to re-check.

What is charged

Pay per event (prices are on the Pricing tab):

  • location-check — once per location whose observation window was read successfully. Charged also when nothing changed, because the summary row (unanswered count, reply rate, …) is produced on every run. Not charged for failed, partial, notStarted and budgetLimited-before-check locations.
  • change — once per change row stored in the dataset.

locationSummary and runSummary rows are free. If the run reaches your max cost per run, the Actor stops cleanly: the number of change rows stored equals the number charged and the number reported in changeRowsSaved; remaining locations are notStarted and not requested. locationCheckCharged on each summary row and locationChecksCharged on the run summary show the checks charged.

Example: 50 locations checked daily with 40 changes a day = 50 location checks + 40 change events per run.

Limits

  • Changes outside the window are not seen. A reply added to a review visited 45 days ago is not reported with windowDays: 30. Use a longer window if stores answer late; reading more reviews does not add change charges.
  • Review text edits and deleted reviews are not reported. A removed owner reply is not reported as an event; the summary row always shows the current unanswered count.
  • Newest visit first only, as listed by Naver. InSample numbers describe the window, not the place's lifetime.
  • Hospitals and clinics: Naver hides star ratings for medical businesses, so rating, avgRatingInSample and placeAvgRating are null there.
  • createdAt comes from the timestamp inside Naver's review ID and is returned only when its Korea-time date matches Naver's own "written" label; otherwise null.
  • Owner reply dates have no year on Naver (e.g. 9.30.수), so they are kept as the original label.
  • Masking is pattern based (e-mail addresses, Korean mobile and landline numbers). Review text is written by users and may still contain personal details they chose to share; handle it accordingly.
  • One run at a time per history name. Two runs sharing a historyStoreName at the same moment can report the same change twice.
  • Timestamps are UTC (Z); Naver's labels are Korea time (KST, UTC+9).
  • The Actor only reads public pages. It does not log in and does not post replies.

Implementation notes

  • Requests go through Apify Proxy with a new proxy session for every attempt, up to 6 attempts with increasing waits. Naver rate-limits repeated requests from one IP (HTTP 429). The first private version of this Actor (0.1) used a shared no-proxy, no-retry request layer and was blocked with HTTP 429 on Apify; version 0.2 replaces that layer, for this Actor only, with the one already used by Naver Place Reviews Scraper.
  • Up to 5 locations are read in parallel; charging, storing and history updates happen one location at a time, in input order. The time of the last completed check of all locations is kept in one checkpoints record, so a location with no changes needs no storage write of its own.
  • Tests: npm test runs the offline regression suite (429 retries, cost limit, reply change detection, masking, history).