Selenium Naver CAPTCHA Fix 2026 — The $cdc_ Variable After 7 Failed Attempts
A Selenium-based Naver auto-login script ran perfectly for over a year. Then one day, CAPTCHAs started appearing on roughly 50% of login attempts. Nothing had changed in the code. Manual login from the same computer, same IP — zero CAPTCHAs. Selenium login — CAPTCHA half the time. After 7 rounds of debugging and failed fixes, the real culprit turned out to be the $cdc_ variable that chromedriver injects into the DOM. undetected-chromedriver patches that variable out and completely eliminates the CAPTCHA problem.
The Problem — CAPTCHAs Appearing After 1 Year of Smooth Operation
The automation script was built in early 2025 for logging into Naver and scraping data from specific pages. It ran without a single issue for an entire year. Then in March 2026, CAPTCHAs started showing up on every other run.
The pattern was irregular — two successful runs, then a CAPTCHA, three more successes, then another CAPTCHA. It wasn't an IP ban or account lockout. Manual login worked flawlessly every time. The code hadn't been modified.
Initial suspects that were ruled out:
Naver server instability — persisted for days. IP blocking — same behavior from different IPs. Account issues — manual login worked perfectly. Chrome update — this turned out to be relevant, but wasn't obvious at first.
Attempts 1-3: User-Agent, Stealth Scripts, Persistent Profile
Attempt 1: User-Agent hardcoding fix — made things worse.
The existing code had Chrome/114.0.0.0 hardcoded in the User-Agent, but the actual Chrome version was 146. Updating to 146 had no effect — the CAPTCHA rate actually increased slightly. The reason became clear later: hardcoding the UA itself was the problem.
# Original code (Chrome 114 hardcoded — the initial mistake)
options.add_argument("user-agent=Mozilla/5.0 ... Chrome/114.0.0.0 Safari/537.36")
# Attempt 1 (Changed to Chrome 146 — still hardcoded, still a problem)
options.add_argument("user-agent=Mozilla/5.0 ... Chrome/146.0.0.0 Safari/537.36")Attempt 2: Stealth CDP script injection — marginal improvement.
A widely-known bot detection bypass technique: setting navigator.webdriver to false and injecting CDP (Chrome DevTools Protocol) scripts to remove automation traces. CAPTCHAs decreased slightly but didn't disappear. Naver had likely already adapted to this well-known approach.
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": """
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
window.navigator.chrome = { runtime: {} };
"""
})Attempt 3: Persistent Chrome profile — partial improvement.
Instead of launching a fresh Chrome instance each time, a persistent profile directory was configured to retain login cookies and browser history. This mimics a real user with "frequently visited sites." The CAPTCHA rate dropped noticeably, but new or empty profiles still triggered CAPTCHAs.
options.add_argument("--user-data-dir=/home/user/chrome-profile")
options.add_argument("--profile-directory=Default")Attempts 4-6: Delays, WebDriverWait Speed, Direct CDP Execution
Attempt 4: Random delays between actions — no meaningful effect.
Added 1-3 second random delays between clicks and inputs to simulate human behavior, plus extra wait time after page loads. No perceptible improvement. Once the $cdc_variable flags the session as a bot, behaving slowly doesn't help.
Attempt 5: WebDriverWait for immediate input — slight improvement.
Reversed the approach: instead of "act slowly," try "act fast." The idea was to complete input before Naver's bot detection script loads. Using WebDriverWait to type immediately when elements appear improved the success rate slightly — but it was luck-based. When timing aligned, it worked; otherwise, it failed.
Attempt 6: Direct CDP without chromedriver — too unstable.
Removed chromedriver entirely and launched Chrome with--remote-debugging-port, controlling it directly via CDP. In theory, no chromedriver means no $cdc_ variable. In practice, Chrome startup was unreliable — port binding failures, intermittent debugging connection drops. Stability was too low for production use.
Attempt 7: undetected-chromedriver — Complete Fix
After 6 failures, digging through Stack Overflow and GitHub issues led to undetected-chromedriver (UC) — a library that patches the chromedriver binary itself to remove bot detection markers. Installed it skeptically. From that day forward, CAPTCHAs completely disappeared. 100 runs, zero CAPTCHAs.
# Install undetected-chromedriver
pip install undetected-chromedriver# Original code → UC replacement (drop-in)
# Before
from selenium import webdriver
driver = webdriver.Chrome(options=options)
# After
import undetected_chromedriver as uc
driver = uc.Chrome(options=options)
# Done. All existing code works as-isAfter switching to UC, hundreds of test runs over several days produced zero CAPTCHAs. The stealth scripts and persistent profile settings can be kept or removed — they're no longer necessary.
Why Naver Detects Bots — The $cdc_ Variable Explained
So why did everything work for a year, then suddenly break? Two likely causes:
| Detection Method | Description | Importance |
|---|---|---|
| $cdc_ variable | A unique marker variable that chromedriver injects into the DOM. Its presence flags the session as automated | Critical |
| navigator.webdriver | A flag Selenium sets to true. Can be hidden via CDP but the fix is incomplete | Secondary |
| UA/TLS mismatch | Mismatch between User-Agent version string and actual Chrome version triggers detection | Secondary |
| Behavioral patterns | Input speed, mouse movement patterns, and other non-human behavior signatures | Minor |
What UC does is straightforward. It downloads the chromedriver binary, replaces the $cdc_ string with a different value, and launches Chrome with the patched driver. No bot marker gets injected into the DOM.
Why it broke after 1 year: Most likely a combination of Naver strengthening its bot detection logic and accumulated Chrome version mismatches in the hardcoded User-Agent crossing a detection threshold. Not a single cause, but compounding factors.
Final Working Code
The production version currently running without issues. UA hardcoding removed, switched to undetected-chromedriver.
# naver_login.py — final version
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import random
def create_driver():
options = uc.ChromeOptions()
# Persistent profile (maintains login state)
options.add_argument("--user-data-dir=/home/user/chrome-profile")
options.add_argument("--profile-directory=Default")
# No UA hardcoding — use Chrome's real UA automatically
driver = uc.Chrome(options=options)
return driver
def naver_login(driver, username, password):
driver.get("https://nid.naver.com/nidlogin.login")
wait = WebDriverWait(driver, 10)
# Enter username
id_field = wait.until(EC.element_to_be_clickable((By.ID, "id")))
time.sleep(random.uniform(0.5, 1.0))
id_field.click()
for ch in username:
id_field.send_keys(ch)
time.sleep(random.uniform(0.05, 0.15))
# Enter password
pw_field = wait.until(EC.element_to_be_clickable((By.ID, "pw")))
time.sleep(random.uniform(0.3, 0.8))
pw_field.click()
for ch in password:
pw_field.send_keys(ch)
time.sleep(random.uniform(0.05, 0.15))
# Click login button
time.sleep(random.uniform(0.5, 1.0))
login_btn = driver.find_element(By.ID, "log.login")
login_btn.click()
time.sleep(2)
return "nid.naver.com/nidlogin" not in driver.current_urlSummary
Naver's primary bot detection relies on the $cdc_ variable that chromedriver injects into the DOM. This is the single most important detection signal.
undetected-chromedriver patches the chromedriver binary to replace the $cdc_ string, preventing the bot marker from being injected. It's a drop-in replacement — change the import and constructor, everything else stays the same.
Never hardcode User-Agent strings. Let Chrome send its real UA automatically. Version mismatches between hardcoded UA and actual Chrome create additional detection signals.
Persistent profiles provide supplementary protection by maintaining login cookies and browsing history, but they don't solve the core $cdc_ issue.
Stealth scripts and random delays are secondary at best. Once the $cdc_ variable flags a session as automated, no amount of human-like behavior simulation overcomes that detection.
This article is based on real experience from March 2026. Naver's bot detection policies are updated regularly, so this method is not guaranteed to work permanently. Always check the service's terms of use and robots.txt before deploying automation scripts.