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
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:[email protected] :8080"
proxy.ssl_proxy = "user:[email protected] :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