# Naver Blog Scraper — Sponsored Ad Detector + Keyword Volume (`ntriqpro/naver-blog-scraper`) Actor

Scrape Naver Blog posts by keyword: full content, tags, sponsored-vs-authentic ad detection, monthly keyword search volume and blogger rankings. Korean-native classifier. Unofficial tool, not affiliated with Naver.

- **URL**: https://apify.com/ntriqpro/naver-blog-scraper.md
- **Developed by:** [Daniel Carter](https://apify.com/ntriqpro) (community)
- **Categories:** SEO tools, Social media, Automation
- **Features:** Limited permissions
- **Stats:** 13 total users, 5 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.16 / 1,000 keyword stats

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/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 Blog Scraper — Sponsored Ad Detector + Keyword Volume

Scrape **Naver Blog** — Korea's dominant blogging platform — by keyword or post URL, and get three things no generic scraper gives you:

1. **Full posts** — title, body text, hashtags, image count, blogger, date
2. **Sponsored-ad detection** — a Korean-native classifier flags whether each post is a paid/sponsored review or an authentic "bought it with my own money" (*naedon-naesan*) post
3. **Keyword search volume** — monthly PC/mobile search counts, average clicks and competition level for your keyword and its related keywords, plus a **blogger ranking** for each keyword

Built by a Korean team. Korean marketing content lives and dies by the sponsored/authentic distinction — this Actor reads the actual Korean disclosure phrasing ("paid a small fee for the post", "provided by the company", "review-team participant", "bought with my own money" …), not just metadata.

> **Unofficial tool.** This Actor is not affiliated with, endorsed by, or sponsored by Naver Corporation. It collects only publicly accessible posts — no login, no private data.

#### Free plan vs paid plan

| | Apify free plan | Any paid Apify plan |
|---|---|---|
| Keywords per run | **1** (the rest are counted as not searched) | Up to 10 |
| `post` rows (full body, tags, sponsored/authentic verdict) | **10** a run (keyword posts and direct URLs together) | Up to `maxPostsPerKeyword` per keyword (1,000 max) |
| `keyword-stats` rows | **1** (your keyword's own volume row) | Your keyword plus up to 29 related keywords |
| `blogger` ranking rows | **1** (the top blogger) | Up to 20 per keyword |
| Locked rows | Counted exactly in a final `free-plan-preview` row and status message (posts, keyword-volume rows and bloggers held back, with their list price) | Nothing locked |
| Price per event | List price | Bronze 20% off · Silver 35% off · Gold and above 48% off |

### What you get (row types)

Every run returns one flat dataset. Filter by `rowType`:

#### `post` — one row per blog post

| Field | Description |
| --- | --- |
| `keyword` | The search keyword that found this post (null for direct URLs) |
| `postTitle` | Post title |
| `url` | Post URL |
| `blogId` / `logNo` | Naver identifiers |
| `bloggerName` / `blogUrl` | Author |
| `postDate` | Publication date (`YYYY-MM-DD`) |
| `snippet` | Search-result summary |
| `sponsoredVerdict` | `sponsored` | `authentic` | `unknown` |
| `sponsoredSignals` | Which disclosure phrases matched, labelled in Korean as the post wrote them (e.g. the "sponsorship" and "review team" markers) |
| `authenticSignals` | Which authenticity phrases matched, labelled in Korean as the post wrote them (e.g. the *naedon-naesan* marker) |
| `contentStatus` | `ok` | `skipped` | `unavailable` | `http_403` … — how the content fetch went |
| `content` | Full body text (up to 20,000 chars) |
| `contentLength` | Full body length in characters |
| `tags` | Hashtags found in the post |
| `imageCount` / `videoCount` | Media counts |

#### `keyword-stats` — monthly search volume (per keyword, incl. related keywords)

| Field | Description |
| --- | --- |
| `inputKeyword` | Your keyword |
| `keyword` | This row's keyword (your keyword or a related one) |
| `isInputKeyword` | `true` on the row for your exact keyword |
| `monthlySearchesPc` / `monthlySearchesMobile` / `monthlySearchesTotal` | Monthly Naver search counts |
| `under10Flag` | `true` when Naver reports "fewer than 10" (value shown as 5) |
| `monthlyAvgClicksPc` / `monthlyAvgClicksMobile` | Average monthly ad clicks |
| `competition` | Naver's competition level, returned as the Korean words for low / medium / high |

#### `blogger` — who owns this keyword (per keyword, top 20)

| Field | Description |
| --- | --- |
| `keyword` / `rank` | Keyword and rank by post count |
| `blogId` / `bloggerName` / `blogUrl` | The blogger |
| `postCount` | Posts by this blogger in the collected set |
| `sponsoredCount` / `authenticCount` / `sponsoredRatio` | How much of their output is sponsored |
| `latestPostDate` | Most recent post in the set |

Status rows (`noticeCode` + `message`) explain anything that could not be collected and are **not charged** — with one exception that is a result you asked for: a **target verdict** (`no-results`: the search completed and Naver has no posts for the keyword; `post-unavailable`: Naver answered that a direct post URL is deleted, private or blocked — 403/404/410/429). Those are charged once as `target-verdict` **only when that event is on the Actor's price list**. A fetch that did not finish on our side (timeout, network error, Naver 5xx) is reported as `post-fetch-failed` and never charged; so are `search-failed` and `keyword-stats-failed`.

### Input

```json
{
    "keywords": ["jeju restaurant", "gangnam dermatology"],
    "maxPostsPerKeyword": 100,
    "sort": "sim",
    "fetchContent": true,
    "includeKeywordStats": true,
    "includeBloggerStats": true
}
```

- `keywords` — up to 10 per run; each returns up to 1,000 posts
- `postUrls` — scrape specific posts directly (`blog.naver.com/{blogId}/{logNo}`)
- `fetchContent: false` — faster metadata-only run (classifier then sees title + snippet only)
- `sort` — `sim` (relevance) or `date` (newest first)

### Use cases

- **Sponsored-review auditing** — separate paid placements from authentic reviews for any brand, product or place keyword
- **Influencer discovery** — the blogger ranking shows who dominates a keyword and how sponsored their output is
- **Korean SEO & content planning** — real monthly search volume and competition per keyword, straight from Naver's data
- **Brand monitoring** — track what Korean consumers write about you, with full text for sentiment analysis
- **Market research** — Naver Blog is where Korean purchase research happens; this is that data, structured

### Pricing

Pay per event: a small per-run start fee, then per delivered row — `post`, `keyword-stats` and `blogger` rows are billed at their own rates (see the Pricing tab). `target-verdict` ($0.004, the `post` rate) is billed per completed target verdict row (see above) once that event is on the price list. Other status/notice rows are free. Each billable row is delivered first and charged right after; when your run's maximum cost is reached the run stops before the next billable row and ends SUCCEEDED.

**What a run actually costs.** One keyword on default settings returned 25 billable rows — 10 `keyword-stats`, 10 `post`, 5 `blogger` — for **$0.151**. Ten keywords in one run land near **$1.50**. Rows scale with what you ask for: raise `maxPostsPerKeyword` and you pay for the extra posts, nothing else. Exact per-row rates are on the Pricing tab.

The start fee applies to every run, including a run started with no keyword and no post URL: that run ends SUCCEEDED with a `no-input` notice row saying what was missing, and the start fee is its only charge.

Until `target-verdict` is on the price list, a keyword where Naver returns nothing is not charged beyond the run start fee. Once it is, that completed empty answer is billed once as `target-verdict`.

### Fair collection

- Only publicly accessible posts — no login, no captcha bypass, no private cafes
- Post pages are fetched with an honest bot User-Agent and polite concurrency
- Deleted/private posts are reported as `post-unavailable` status rows (billed as `target-verdict` only once that event is on the price list)
- Personal data: rows contain only what the blogger publicly displays (public nickname, public blog URL). Use downstream in compliance with applicable law (e.g. PIPA, GDPR); you are the controller of what you do with the data.

### Limitations

- Naver search pagination tops out at 1,000 posts per keyword
- The sponsored classifier reads visible text; a sponsored post with no disclosure text anywhere is classified `unknown`, not `sponsored`
- Comment threads are not collected in this version

### Works well with

- **[coupang-review-intelligence](https://apify.com/ntriqpro/coupang-review-intelligence)** — Turn the same keyword into real buyer reviews and a product verdict from Coupang.
- **[lighthouse-website-audit](https://apify.com/ntriqpro/lighthouse-website-audit)** — Score the landing page you are driving that Naver traffic to.

Every run of this Actor also returns these suggestions in the `nextSteps` field of its summary row.

### Leave a review

A short review on the **Reviews** tab, good or bad, helps other people find this Actor and tells us what to build next. Found a bug or need a feature? Open an issue on the **Issues** tab and we'll look into it.

# Actor input Schema

## `keywords` (type: `array`):

One or more keywords to search on Naver Blog. Korean keywords return the richest results (Korean keyword), English works too. Each keyword returns up to 1,000 posts plus its monthly search-volume rows and a blogger ranking. Max 10 keywords per run. Apify free plan: 1 keyword, 10 post rows, 1 keyword-volume row and 1 blogger row a run, plus a free-plan-preview row counting what was held back.

## `postUrls` (type: `array`):

Specific Naver Blog post URLs to scrape directly (blog.naver.com/{blogId}/{logNo} or m.blog.naver.com links). Combine freely with keywords. Max 100 per run.

## `maxPostsPerKeyword` (type: `integer`):

How many posts to collect for each keyword. 1-1000 (Naver's search pagination ceiling). Fetching full content takes roughly 0.2-0.4s per post at the default concurrency.

## `sort` (type: `string`):

Relevance (sim) or newest first (date).

## `fetchContent` (type: `boolean`):

On by default: each post's full body text, hashtags and image count are extracted, and the sponsored/authentic classifier runs on the full text. Turn off for a faster metadata-only run (the classifier then sees only title and snippet).

## `includeKeywordStats` (type: `boolean`):

On by default: for each keyword, adds rows with monthly PC/mobile search volume, average clicks and competition level (from Naver's advertising keyword tool), including related keywords.

## `includeBloggerStats` (type: `boolean`):

On by default: for each keyword, adds a ranking of the bloggers behind the collected posts — post count, sponsored ratio, latest post date.

## `maxConcurrency` (type: `integer`):

Parallel workers for post-content fetching. 1-10. The default is polite to Naver's servers.

## `maxResults` (type: `integer`):

Stop after this many billable rows (all row types combined). 1-5000.

## `maxRunSecs` (type: `integer`):

Soft deadline for the whole run. When reached, the run stops fetching and returns everything collected so far as a successful run. 60-21600.

## Actor input object example

```json
{
  "keywords": [
    "제주도 맛집"
  ],
  "postUrls": [],
  "maxPostsPerKeyword": 30,
  "sort": "sim",
  "fetchContent": true,
  "includeKeywordStats": true,
  "includeBloggerStats": true,
  "maxConcurrency": 5,
  "maxResults": 1000,
  "maxRunSecs": 900
}
```

# Actor output Schema

## `dataset` (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 = {
    "keywords": [
        "제주도 맛집"
    ],
    "postUrls": [],
    "maxPostsPerKeyword": 30,
    "fetchContent": true,
    "includeKeywordStats": true,
    "includeBloggerStats": true,
    "maxConcurrency": 5,
    "maxResults": 1000,
    "maxRunSecs": 900
};

// Run the Actor and wait for it to finish
const run = await client.actor("ntriqpro/naver-blog-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 = {
    "keywords": ["제주도 맛집"],
    "postUrls": [],
    "maxPostsPerKeyword": 30,
    "fetchContent": True,
    "includeKeywordStats": True,
    "includeBloggerStats": True,
    "maxConcurrency": 5,
    "maxResults": 1000,
    "maxRunSecs": 900,
}

# Run the Actor and wait for it to finish
run = client.actor("ntriqpro/naver-blog-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 '{
  "keywords": [
    "제주도 맛집"
  ],
  "postUrls": [],
  "maxPostsPerKeyword": 30,
  "fetchContent": true,
  "includeKeywordStats": true,
  "includeBloggerStats": true,
  "maxConcurrency": 5,
  "maxResults": 1000,
  "maxRunSecs": 900
}' |
apify call ntriqpro/naver-blog-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ntriqpro/naver-blog-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/KS59RSKOeW8eXr8aR/builds/0ke8SokperNIIdxk7/openapi.json
