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

Scrape Naver Blog posts by keyword: full content, tags, sponsored-vs-내돈내산 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:** [daehwan kim](https://apify.com/ntriqpro) (community)
- **Categories:** SEO tools, Social media, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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 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" (내돈내산) 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 (소정의 원고료, 업체로부터 제공, 체험단, 내돈내산 …), 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.

### 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 (e.g. `["협찬", "체험단"]`) |
| `authenticSignals` | Which authenticity phrases matched (e.g. `["내돈내산"]`) |
| `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: 낮음 / 중간 / 높음 |

#### `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 — a deleted post, an unavailable keyword — and are **never charged**.

### Input

```json
{
    "keywords": ["제주도 맛집", "강남 피부과"],
    "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). Status/notice rows are free. Free-plan runs return up to 25 rows, prioritising the highest-value rows (keyword volume → blogger ranking → posts).

**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.

Status/notice rows are never billed. That includes runs where Naver returns nothing for a keyword — you are not charged for an empty answer.

### 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 status rows and not charged
- 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

# Actor input Schema

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

One or more keywords to search on Naver Blog. Korean keywords return the richest results (e.g. 제주도 맛집), 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.

## `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/DMTppVfSsI848aGw8/openapi.json
