Skip to main content

Overview

While Undetected works best with default settings, there are legitimate cases where you need to customize Chrome’s behavior. This guide shows how to use ChromeOptions safely without triggering bot detection.
From the source code (undetected/init.py:58-63):
Chrome has everything included to work out of the box. It does not need customizations. Any customizations MAY lead to trigger bot mitigation systems.
Use custom options sparingly and test thoroughly.

Creating ChromeOptions

Undetected provides its own ChromeOptions class that extends Selenium’s options:
import undetected as uc

options = uc.ChromeOptions()
driver = uc.Chrome(options=options)
Never reuse ChromeOptions objects:
# ❌ WRONG - Will raise RuntimeError
options = uc.ChromeOptions()
driver1 = uc.Chrome(options=options)
driver2 = uc.Chrome(options=options)  # Error!
Each driver instance requires fresh options.

Common Arguments

Window Size and Position

Control the browser window dimensions:
import undetected as uc

options = uc.ChromeOptions()
options.add_argument("--window-size=1920,1080")
options.add_argument("--start-maximized")

driver = uc.Chrome(options=options)
Undetected automatically adds --window-size=1920,1080 and --start-maximized (undetected/init.py:359-360).

Headless Mode

Run Chrome without a visible window:
import undetected as uc

# Method 1: Via constructor
driver = uc.Chrome(headless=True)

# Method 2: Via options
options = uc.ChromeOptions()
options.headless = True
driver = uc.Chrome(options=options)
The library automatically uses the correct headless flag based on Chrome version:
  • Chrome < 108: --headless=chrome
  • Chrome >= 108: --headless=new

Language Settings

Set the browser language:
import undetected as uc

options = uc.ChromeOptions()
options.add_argument("--lang=es-ES")

driver = uc.Chrome(options=options)
If no language is specified, Undetected automatically uses your system locale or defaults to en-US (undetected/init.py:315-331).

Disable Logging

Reduce console output:
import undetected as uc

options = uc.ChromeOptions()
options.add_argument("--log-level=3")  # Only fatal errors

driver = uc.Chrome(options=options, log_level=3)
Log levels:
  • 0 - INFO (default)
  • 1 - WARNING
  • 2 - ERROR
  • 3 - FATAL

No Sandbox Mode

Required when running as root (Linux):
import undetected as uc

options = uc.ChromeOptions()
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")  # Overcome limited resource problems

driver = uc.Chrome(options=options)
Undetected automatically adds --no-sandbox and --test-type when no_sandbox=True (default) (undetected/init.py:342-343).

User Preferences

Set Chrome preferences using experimental options:
import undetected as uc

options = uc.ChromeOptions()

# Download settings
prefs = {
    "download.default_directory": "/path/to/downloads",
    "download.prompt_for_download": False,
    "download.directory_upgrade": True,
    "safebrowsing.enabled": True
}

options.set_experimental_option("prefs", prefs)
driver = uc.Chrome(options=options)

Common Preferences

Disable Images

Speed up page loads:
prefs = {
    "profile.managed_default_content_settings.images": 2
}
options.set_experimental_option("prefs", prefs)

Disable Notifications

prefs = {
    "profile.default_content_setting_values.notifications": 2
}
options.set_experimental_option("prefs", prefs)

Set Download Behavior

prefs = {
    "download.default_directory": "/tmp/downloads",
    "download.prompt_for_download": False,
    "plugins.always_open_pdf_externally": True
}
options.set_experimental_option("prefs", prefs)

User Data Directory

Use a persistent profile to maintain cookies and settings:
import undetected as uc

# Method 1: Via constructor (recommended)
driver = uc.Chrome(user_data_dir="/path/to/profile")

# Method 2: Via options argument
options = uc.ChromeOptions()
options.add_argument("--user-data-dir=/path/to/profile")
driver = uc.Chrome(options=options)

# Method 3: Via options property (deprecated)
options = uc.ChromeOptions()
options.user_data_dir = "/path/to/profile"
driver = uc.Chrome(options=options)
Method 3 (using the property) is deprecated and may stop working in future versions. Use the constructor parameter instead.

Profile Lifecycle

  • No user_data_dir specified: A temporary profile is created and deleted on quit()
  • user_data_dir specified: The profile persists after quit()

Binary Location

Use a specific Chrome installation:
import undetected as uc

# Via constructor
driver = uc.Chrome(browser_executable_path="/usr/bin/google-chrome-stable")

# Via options
options = uc.ChromeOptions()
options.binary_location = "/usr/bin/google-chrome-stable"
driver = uc.Chrome(options=options)
If not specified, Undetected automatically finds Chrome in standard locations.

Capabilities

Set custom capabilities for advanced scenarios:
import undetected as uc

options = uc.ChromeOptions()

# Platform-specific capability
options.set_capability("platformName", "linux")

# Page load strategy
options.set_capability("pageLoadStrategy", "eager")

driver = uc.Chrome(options=options)

Page Load Strategies

  • normal (default): Wait for all resources
  • eager: Wait for DOM, but not all resources
  • none: Return immediately

Chrome DevTools Protocol (CDP)

Enable CDP Events

Listen to browser events:
import undetected as uc

def handle_network_event(data):
    print(f"Network event: {data}")

driver = uc.Chrome(enable_cdp_events=True)
driver.add_cdp_listener("Network.dataReceived", handle_network_event)

driver.get("https://example.com")
driver.quit()
When enable_cdp_events=True, the library automatically sets performance and browser logging capabilities (undetected/init.py:244-246).

Execute CDP Commands

Direct CDP command execution:
import undetected as uc
import base64

driver = uc.Chrome()
driver.get("https://example.com")

# Generate PDF
pdf_data = driver.execute_cdp_cmd("Page.printToPDF", {})
with open("page.pdf", "wb") as f:
    f.write(base64.b64decode(pdf_data["data"]))

driver.quit()

Proxy Configuration

Use a proxy server:
import undetected as uc

options = uc.ChromeOptions()
options.add_argument("--proxy-server=http://proxy.example.com:8080")

driver = uc.Chrome(options=options)
With authentication:
import undetected as uc
from selenium.webdriver.common.proxy import Proxy, ProxyType

proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "user:pass@proxy.example.com:8080"
proxy.ssl_proxy = "user:pass@proxy.example.com:8080"

options = uc.ChromeOptions()
proxy.add_to_capabilities(options.to_capabilities())

driver = uc.Chrome(options=options)

Advanced Element Representation

Improve debugging with human-readable element representations:
import undetected as uc

driver = uc.Chrome(advanced_elements=True)
driver.get("https://example.com")

element = driver.find_element("id", "my-link")

# Default representation:
# <selenium.webdriver.remote.webelement.WebElement (session="...", element="...")>

# Advanced representation:
print(element)
# <WebElement(<a class="link" href="#" id="my-link">)>
This feature may slow down operations when retrieving large numbers of elements.

Suppress Welcome Dialogs

Disable first-run dialogs (enabled by default):
import undetected as uc

# Dialogs are suppressed by default
driver = uc.Chrome()  # suppress_welcome=True (default)

# To enable welcome dialogs
driver = uc.Chrome(suppress_welcome=False)
When enabled, adds:
  • --no-default-browser-check
  • --no-first-run

Complete Configuration Example

Here’s a comprehensive example combining multiple options:
import undetected as uc
import os

# Set up options
options = uc.ChromeOptions()

# Window settings
options.add_argument("--window-size=1920,1080")
options.add_argument("--start-maximized")

# Performance
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--no-sandbox")

# Language
options.add_argument("--lang=en-US")

# Preferences
prefs = {
    "download.default_directory": os.path.expanduser("~/Downloads"),
    "download.prompt_for_download": False,
    "profile.default_content_setting_values.notifications": 2,
    "profile.managed_default_content_settings.images": 1,  # Enable images
}
options.set_experimental_option("prefs", prefs)

# Create driver
driver = uc.Chrome(
    options=options,
    user_data_dir="/path/to/profile",
    headless=False,
    enable_cdp_events=False,
    advanced_elements=False,
    log_level=1,
)

driver.get("https://example.com")
driver.quit()

Testing Custom Options

Always test your custom configuration against bot detection:
import undetected as uc

options = uc.ChromeOptions()
# ... add your custom options ...

driver = uc.Chrome(options=options)

# Test against bot detection
driver.get("https://bot.incolumitas.com")
driver.get("https://nowsecure.nl")

# Check for detection
print(driver.page_source)

driver.quit()

Best Practices

Only add options that are absolutely necessary. Each custom argument increases the risk of detection.
Browser extensions significantly increase your detection fingerprint. They are not recommended and may lower undetectability.
Always test custom configurations against real bot detection systems before deploying to production.
Create a new ChromeOptions() instance for each driver. Never reuse options objects.

Next Steps