Naver Open API (Search, Papago, Clova)
Naver's consumer-facing Open API suite — provides programmatic access to South Korea's dominant search engine (70%+ market share), Papago translation, Clova OCR/AI services, Naver Maps, and Naver Login (OAuth). No official Python SDK exists — integration is done via direct HTTP requests using the requests library. Auth uses Client ID and Client Secret passed as HTTP headers. All APIs are registered and managed via the Naver Cloud Platform console. IMPORTANT: Naver Open API is Korea-first — registration UI, documentation, and error messages are primarily in Korean. Daily quota resets at 00:00 KST (UTC+9), not UTC.
Warnings
- gotcha Two different base URLs serve different API categories. Search and Login APIs use 'https://openapi.naver.com'. AI/ML services (Papago translation, Clova OCR, CLOVA Speech) use 'https://naveropenapi.apigw.ntruss.com'. Using the wrong base URL returns a 404 or auth error with no indication of the actual problem.
- gotcha Daily quota resets at 00:00 KST (Korea Standard Time, UTC+9), not UTC. If you're in UTC or UTC-8, your quota resets at 15:00 or 08:00 UTC respectively — not midnight local time. Rate limit errors return HTTP 429.
- gotcha Registering an application in the console does not automatically enable all APIs. Each service must be explicitly selected/enabled per application via the console Edit Application flow. Calling an API that hasn't been enabled for the application returns HTTP 429 (Quota Exceed) — not a 403 or 401 — which makes the error appear to be a rate limit issue rather than a misconfiguration.
- gotcha No official Python SDK exists. Community packages on PyPI (napit, NaverTTS) are unmaintained and target old API versions. LLM-generated code often invents a 'naver' or 'naver-sdk' package that does not exist.
- gotcha Search API pagination is limited: maximum 1000 results total (start + display ≤ 1001), maximum 100 results per page. Attempting to paginate beyond this returns an error. There is no cursor-based pagination.
- gotcha Naver Open API registration, console UI, and official documentation are primarily in Korean. The English documentation at api.ncloud-docs.com is a translation that lags behind the Korean source and may be incomplete for newer services.
- gotcha Naver Search API returns Korean-language content by default. The API does not filter by language — all results are from Naver's Korean index. Non-Korean queries return results but content will be predominantly Korean.
Install
-
pip install requests
Imports
- requests
import requests
Quickstart
import os
import requests
CLIENT_ID = os.environ['NAVER_CLIENT_ID'] # X-NCP-APIGW-API-KEY-ID
CLIENT_SECRET = os.environ['NAVER_CLIENT_SECRET'] # X-NCP-APIGW-API-KEY
headers = {
'X-NCP-APIGW-API-KEY-ID': CLIENT_ID,
'X-NCP-APIGW-API-KEY': CLIENT_SECRET,
}
# --- Search API (blog, news, web, image, shopping, book) ---
# Base URL: https://openapi.naver.com/v1/search/{type}.json
def search_blog(query: str, display: int = 10, start: int = 1):
url = 'https://openapi.naver.com/v1/search/blog.json'
params = {
'query': query,
'display': display, # 1-100, default 10
'start': start, # 1-1000
'sort': 'sim', # 'sim' (relevance) or 'date'
}
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
return response.json()
def search_news(query: str):
url = 'https://openapi.naver.com/v1/search/news.json'
params = {'query': query, 'display': 10, 'sort': 'date'}
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
return response.json()
# --- Papago Translation ---
# Supported language pairs: ko<->en, ko<->zh-CN, ko<->zh-TW, ko<->ja, ko<->es, ko<->fr, etc.
def translate(text: str, source: str = 'ko', target: str = 'en'):
url = 'https://naveropenapi.apigw.ntruss.com/nmt/v1/translation'
# NOTE: Papago uses different base URL than Search API
data = {
'source': source,
'target': target,
'text': text,
}
response = requests.post(url, headers=headers, data=data)
response.raise_for_status()
return response.json()['message']['result']['translatedText']
# --- Clova OCR ---
def ocr_image(image_url: str):
url = 'https://naveropenapi.apigw.ntruss.com/ocr/v1/recognize'
data = {
'image': image_url,
'lang': 'ko',
'type': 'url',
}
response = requests.post(url, headers=headers, data=data)
response.raise_for_status()
return response.json()
# --- Naver Login (OAuth 2.0) ---
# Step 1: Redirect user to Naver auth URL
import urllib.parse
def get_naver_login_url(state: str) -> str:
params = {
'response_type': 'code',
'client_id': CLIENT_ID,
'redirect_uri': 'https://yourdomain.com/callback',
'state': state,
}
return 'https://nid.naver.com/oauth2.0/authorize?' + urllib.parse.urlencode(params)
# Step 2: Exchange code for token
def get_naver_token(code: str, state: str) -> dict:
url = 'https://nid.naver.com/oauth2.0/token'
params = {
'grant_type': 'authorization_code',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'code': code,
'state': state,
}
response = requests.get(url, params=params)
return response.json()
# Step 3: Get user profile
def get_naver_profile(access_token: str) -> dict:
url = 'https://openapi.naver.com/v1/nid/me'
headers_auth = {'Authorization': f'Bearer {access_token}'}
response = requests.get(url, headers=headers_auth)
return response.json()