{"id":49,"library":"naver-openapi","title":"Naver Open API (Search, Papago, Clova)","description":"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.","status":"active","version":"N/A (REST API — no versioned Python package)","language":"python","source_language":"ko","source_url":"https://api.ncloud-docs.com/docs/en/common-naverapi-naverapi","tags":["naver","korea","search","papago","translation","clova","ocr","korean-search","naver-login","oauth","korean-market"],"install":[{"cmd":"pip install requests","lang":"bash","label":"Only dependency needed — Naver Open API has no official Python SDK"}],"dependencies":[{"reason":"Required. All Naver Open API calls are plain HTTP requests with Client ID/Secret headers.","package":"requests","optional":false}],"imports":[{"note":"There is no official Naver Python SDK on PyPI. Community packages like 'napit' or 'NaverTTS' exist but are unmaintained. Use raw requests against openapi.naver.com or naveropenapi.apigw.ntruss.com depending on the service.","wrong":"import naver  # no such official package","symbol":"requests","correct":"import requests"}],"quickstart":{"code":"import os\nimport requests\n\nCLIENT_ID = os.environ['NAVER_CLIENT_ID']        # X-NCP-APIGW-API-KEY-ID\nCLIENT_SECRET = os.environ['NAVER_CLIENT_SECRET']  # X-NCP-APIGW-API-KEY\n\nheaders = {\n    'X-NCP-APIGW-API-KEY-ID': CLIENT_ID,\n    'X-NCP-APIGW-API-KEY': CLIENT_SECRET,\n}\n\n# --- Search API (blog, news, web, image, shopping, book) ---\n# Base URL: https://openapi.naver.com/v1/search/{type}.json\ndef search_blog(query: str, display: int = 10, start: int = 1):\n    url = 'https://openapi.naver.com/v1/search/blog.json'\n    params = {\n        'query': query,\n        'display': display,  # 1-100, default 10\n        'start': start,      # 1-1000\n        'sort': 'sim',       # 'sim' (relevance) or 'date'\n    }\n    response = requests.get(url, headers=headers, params=params)\n    response.raise_for_status()\n    return response.json()\n\ndef search_news(query: str):\n    url = 'https://openapi.naver.com/v1/search/news.json'\n    params = {'query': query, 'display': 10, 'sort': 'date'}\n    response = requests.get(url, headers=headers, params=params)\n    response.raise_for_status()\n    return response.json()\n\n# --- Papago Translation ---\n# Supported language pairs: ko<->en, ko<->zh-CN, ko<->zh-TW, ko<->ja, ko<->es, ko<->fr, etc.\ndef translate(text: str, source: str = 'ko', target: str = 'en'):\n    url = 'https://naveropenapi.apigw.ntruss.com/nmt/v1/translation'\n    # NOTE: Papago uses different base URL than Search API\n    data = {\n        'source': source,\n        'target': target,\n        'text': text,\n    }\n    response = requests.post(url, headers=headers, data=data)\n    response.raise_for_status()\n    return response.json()['message']['result']['translatedText']\n\n# --- Clova OCR ---\ndef ocr_image(image_url: str):\n    url = 'https://naveropenapi.apigw.ntruss.com/ocr/v1/recognize'\n    data = {\n        'image': image_url,\n        'lang': 'ko',\n        'type': 'url',\n    }\n    response = requests.post(url, headers=headers, data=data)\n    response.raise_for_status()\n    return response.json()\n\n# --- Naver Login (OAuth 2.0) ---\n# Step 1: Redirect user to Naver auth URL\nimport urllib.parse\n\ndef get_naver_login_url(state: str) -> str:\n    params = {\n        'response_type': 'code',\n        'client_id': CLIENT_ID,\n        'redirect_uri': 'https://yourdomain.com/callback',\n        'state': state,\n    }\n    return 'https://nid.naver.com/oauth2.0/authorize?' + urllib.parse.urlencode(params)\n\n# Step 2: Exchange code for token\ndef get_naver_token(code: str, state: str) -> dict:\n    url = 'https://nid.naver.com/oauth2.0/token'\n    params = {\n        'grant_type': 'authorization_code',\n        'client_id': CLIENT_ID,\n        'client_secret': CLIENT_SECRET,\n        'code': code,\n        'state': state,\n    }\n    response = requests.get(url, params=params)\n    return response.json()\n\n# Step 3: Get user profile\ndef get_naver_profile(access_token: str) -> dict:\n    url = 'https://openapi.naver.com/v1/nid/me'\n    headers_auth = {'Authorization': f'Bearer {access_token}'}\n    response = requests.get(url, headers=headers_auth)\n    return response.json()","lang":"python","description":"Two different base URLs are used depending on the service: 'openapi.naver.com' for Search and Login APIs, 'naveropenapi.apigw.ntruss.com' for AI services (Papago, Clova). Using the wrong base URL returns a 404 with no helpful error message. Daily quota resets at midnight KST (UTC+9), not UTC."},"warnings":[{"fix":"Search/Blog/News/Login → openapi.naver.com. Papago/Clova/OCR → naveropenapi.apigw.ntruss.com. Check each service's API guide for the exact endpoint.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Plan quota-sensitive workloads around KST midnight. Monitor usage via the Naver Cloud Platform console which displays usage in KST.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"After registering an app, go to Edit Application and explicitly select each API service you intend to use. If you receive 429 immediately on a fresh app with no prior calls, this is the cause.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Use raw requests. The API is simple enough that a direct HTTP wrapper is 10-20 lines. Reference the official API guide at api.ncloud-docs.com for exact endpoint paths and parameters.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"For large result sets, use multiple queries with different sort orders (sim/date) or date range filters to work around the 1000-result cap.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Use the Korean documentation at developers.naver.com as the source of truth for the most current API specs. Use DeepL or Papago itself to translate if needed.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"For Korean market research and Korean-language content, this is the correct tool. For multilingual or global search, use a different API.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"Set the required API client credentials (e.g., `NAVER_CLIENT_ID` and `NAVER_CLIENT_SECRET`) as environment variables in your deployment environment or shell before running the application.","message":"API client credentials (e.g., NAVER_CLIENT_ID, NAVER_CLIENT_SECRET) must be provided as environment variables for authentication. Failure to set these variables will result in a KeyError during application startup.","severity":"breaking","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T05:53:30.904Z","next_check":"2026-06-01T00:00:00.000Z","problems":[{"fix":"Double-check the `X-Naver-Client-Id` and `X-Naver-Client-Secret` headers against the values obtained from the Naver Cloud Platform console. Ensure the registered application has access permissions for the specific API being called.","cause":"The Client ID or Client Secret provided in the HTTP headers is incorrect, missing, or the application is not correctly registered in the Naver Developer Center for the specific API you are trying to use.","error":"{\"errorMessage\":\"Authentication failed. (인증에 실패했습니다.)\",\"errorCode\":\"024\"}"},{"fix":"Wait until 00:00 KST for the daily quota to reset. If higher limits are consistently needed, refer to Naver Cloud Platform documentation for information on increasing quotas or paid service plans.","cause":"The daily API call limit (e.g., 25,000 requests per day for many Naver APIs) has been exceeded for your Client ID. The quota resets at 00:00 KST (UTC+9).","error":"{\"errorCode\":\"429\",\"errorMessage\":\"API call quota exceeded.\"}"},{"fix":"Review the Naver Open API documentation for the specific endpoint to ensure all parameters are correctly formatted, within valid ranges, and properly URL-encoded (e.g., using `urllib.parse.quote` in Python).","cause":"One or more of the request parameters (e.g., query string, 'display', 'start', or 'sort' values) are invalid, malformed, or fall outside the allowed range as specified in the API documentation.","error":"{\"errorMessage\": \"Incorrect query request (잘못된 쿼리요청입니다.)\", \"errorCode\": \"SE01\"}"},{"fix":"Install the `requests` library using pip: `pip install requests`.","cause":"The `requests` library, which is commonly used for making HTTP requests in Python and is necessary for integrating with the Naver Open API, is not installed in your Python environment.","error":"ModuleNotFoundError: No module named 'requests'"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.54,"mem_mb":9.6,"disk_size":"70.4M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.38,"mem_mb":9.6,"disk_size":"142M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.74,"mem_mb":10.8,"disk_size":"77.1M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.58,"mem_mb":10.8,"disk_size":"148M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.64,"mem_mb":11.2,"disk_size":"67.6M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.65,"mem_mb":11.2,"disk_size":"139M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.63,"mem_mb":11.6,"disk_size":"64.1M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.61,"mem_mb":11.6,"disk_size":"137M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.5,"mem_mb":9.4,"disk_size":"69.3M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.4,"mem_mb":9.4,"disk_size":"141M"}]},"quickstart_checks":{"last_tested":"2026-05-12","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}