A sophisticated Java implementation of Selenium ChromeDriver that bypasses anti-bot detection systems like Cloudflare, PerimeterX, and others. This library extends the standard ChromeDriver with advanced stealth techniques, human behavior simulation, and intelligent bot detection handling.
This project is inspired by and based on the concepts from the Python undetected-chromedriver by ultrafunkamsterdam, reimplemented in Java with additional features like human behavior simulation and enhanced thread safety.
- Features
- Requirements
- Installation
- Quick Start
- Configuration
- Usage Examples
- API Reference
- Best Practices
- Troubleshooting
- Performance Considerations
- Contributing
- License
- Automatic ChromeDriver Management - No manual driver downloads required
- Stealth JavaScript Injection - Hides automation indicators like
navigator.webdriver - Browser Fingerprint Randomization - Dynamically changes browser fingerprints
- Human Behavior Simulation - Realistic mouse movements, typing, and scrolling
- Bot Detection Monitoring - Detects and handles Cloudflare, CAPTCHAs, and rate limiting
- Thread-Safe Design - Supports concurrent instances without conflicts
- Comprehensive Configuration - Extensive customization options via
DriverConfig
- Removes
navigator.webdriverproperty - Populates realistic
navigator.pluginsarray - Fixes Chrome runtime objects
- Spoofs WebGL vendor and renderer
- Randomizes canvas fingerprints
- Modifies audio context fingerprints
- Handles permission queries realistically
- Fixes screen dimensions in headless mode
- Natural mouse movements with Bezier curves
- Realistic typing with variable speed and typos
- Smooth scrolling with easing functions
- Random idle behaviors
- Page scanning patterns
- Configurable behavior profiles (FAST, NORMAL, CAREFUL)
- Java 11 or higher
- Chrome browser installed
- Maven or Gradle for dependency management
<dependency>
<groupId>com.undetected</groupId>
<artifactId>undetected-chromedriver</artifactId>
<version>1.0.0</version>
</dependency>implementation 'com.undetected:undetected-chromedriver:1.0.0'import com.undetected.chromedriver.UndetectedChromeDriver;
public class QuickStart {
public static void main(String[] args) {
// Create driver with default configuration
UndetectedChromeDriver driver = new UndetectedChromeDriver();
try {
// Navigate to a protected site
driver.get("https://protected-site.com");
// Use the driver like regular Selenium
WebElement element = driver.findElement(By.id("search"));
driver.humanType(element, "undetected selenium");
// Perform human-like click
WebElement button = driver.findElement(By.name("submit"));
driver.humanClick(button);
} finally {
driver.quit();
}
}
}The DriverConfig class provides extensive configuration options:
import com.undetected.chromedriver.config.DriverConfig;
import com.undetected.chromedriver.HumanBehaviorSimulator.BehaviorProfile;
DriverConfig config = DriverConfig.builder()
// Browser options
.headless(false) // Run in headful mode
.windowSize(1920, 1080) // Set window size
.startMaximized(false) // Don't start maximized
// Anti-detection features
.randomizeFingerprint(true) // Enable fingerprint randomization
.humanBehavior(true) // Enable human behavior simulation
.behaviorProfile(BehaviorProfile.NORMAL) // Set behavior speed
// Network configuration
.proxy("http://proxy.example.com:8080") // Set HTTP proxy
.userAgent("Custom User Agent") // Custom user agent
// Driver configuration
.implicitWaitMs(5000) // Implicit wait timeout
.pageLoadTimeoutMs(30000) // Page load timeout
.requireLatestChrome(true) // Use latest Chrome version
// Advanced options
.verboseLogging(false) // Disable verbose logging
.disableImages(false) // Load images normally
.mobileEmulation(false) // Desktop mode
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);import com.undetected.chromedriver.UndetectedChromeDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
public class BasicExample {
public static void main(String[] args) {
UndetectedChromeDriver driver = new UndetectedChromeDriver();
try {
// Navigate to website
driver.get("https://example.com");
// Find and interact with elements
WebElement searchBox = driver.findElement(By.name("q"));
searchBox.sendKeys("selenium automation");
WebElement searchButton = driver.findElement(By.name("btnK"));
searchButton.click();
// Wait for results
Thread.sleep(2000);
// Get page title
System.out.println("Page title: " + driver.getTitle());
} catch (Exception e) {
e.printStackTrace();
} finally {
driver.quit();
}
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
public class HumanBehaviorExample {
public static void main(String[] args) {
// Enable human behavior simulation
DriverConfig config = DriverConfig.builder()
.humanBehavior(true)
.behaviorProfile(BehaviorProfile.NORMAL)
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);
try {
driver.get("https://example.com/form");
// Human-like typing with realistic delays and occasional typos
WebElement nameField = driver.findElement(By.id("name"));
driver.humanType(nameField, "John Doe");
// Smooth scrolling to element
WebElement emailField = driver.findElement(By.id("email"));
driver.humanScrollToElement(emailField);
driver.humanType(emailField, "john.doe@example.com");
// Natural mouse movement and click
WebElement submitButton = driver.findElement(By.id("submit"));
driver.humanClick(submitButton);
// Simulate user reading the page
driver.performRandomActions();
} finally {
driver.quit();
}
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
public class BotDetectionExample {
public static void main(String[] args) {
DriverConfig config = DriverConfig.builder()
.humanBehavior(true)
.randomizeFingerprint(true)
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);
try {
// Navigate to Cloudflare-protected site
driver.get("https://protected-site.com");
// Check if bot detection is active
if (driver.getBotDetectionHandler().isBotDetectionActive()) {
System.out.println("Bot detection detected! Handling...");
// Wait for automatic resolution
boolean resolved = driver.getBotDetectionHandler().handleBotDetection(60);
if (resolved) {
System.out.println("Bot detection bypassed successfully!");
} else {
System.out.println("Failed to bypass bot detection");
}
}
// Check for rate limiting
if (driver.getBotDetectionHandler().isRateLimited()) {
int waitTime = driver.getBotDetectionHandler().getRecommendedWaitTime();
System.out.println("Rate limited. Waiting " + waitTime + " seconds...");
Thread.sleep(waitTime * 1000);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
driver.quit();
}
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class AdvancedConfigExample {
public static void main(String[] args) {
// Custom Chrome arguments
List<String> customArgs = Arrays.asList(
"--disable-blink-features=AutomationControlled",
"--disable-dev-shm-usage",
"--no-sandbox",
"--disable-web-security",
"--disable-features=IsolateOrigins,site-per-process"
);
// Custom preferences
Map<String, Object> prefs = new HashMap<>();
prefs.put("profile.default_content_setting_values.notifications", 2);
prefs.put("profile.default_content_settings.popups", 0);
prefs.put("download.default_directory", "/path/to/downloads");
// Environment variables
Map<String, String> env = new HashMap<>();
env.put("DISPLAY", ":99");
DriverConfig config = DriverConfig.builder()
.headless(false)
.windowSize(1366, 768)
.userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
.additionalArguments(customArgs)
.additionalPreferences(prefs)
.environmentVariables(env)
.driverCachePath("/custom/cache/path")
.logFile("/custom/logs/chromedriver.log")
.pageLoadTimeoutMs(60000)
.implicitWaitMs(10000)
.disableGpu(true)
.disableImages(false)
.acceptInsecureCerts(true)
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);
try {
driver.get("https://example.com");
// Your automation code here
} finally {
driver.quit();
}
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ConcurrentExample {
public static void main(String[] args) {
int numberOfInstances = 5;
ExecutorService executor = Executors.newFixedThreadPool(numberOfInstances);
List<Future<?>> futures = new ArrayList<>();
// Create multiple driver instances concurrently
for (int i = 0; i < numberOfInstances; i++) {
final int instanceNum = i;
Future<?> future = executor.submit(() -> {
DriverConfig config = DriverConfig.builder()
.humanBehavior(true)
.randomizeFingerprint(true)
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);
try {
System.out.println("Instance " + instanceNum + " starting...");
driver.get("https://example.com/page" + instanceNum);
// Perform automation tasks
Thread.sleep(5000);
System.out.println("Instance " + instanceNum + " completed: " +
driver.getTitle());
} catch (Exception e) {
e.printStackTrace();
} finally {
driver.quit();
}
});
futures.add(future);
}
// Wait for all instances to complete
futures.forEach(future -> {
try {
future.get();
} catch (Exception e) {
e.printStackTrace();
}
});
executor.shutdown();
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
import com.undetected.chromedriver.HumanBehaviorSimulator.BehaviorProfile;
public class BehaviorProfileExample {
public static void main(String[] args) {
// Fast profile - for quick automation
testWithProfile(BehaviorProfile.FAST, "Fast automation");
// Normal profile - balanced speed and realism
testWithProfile(BehaviorProfile.NORMAL, "Normal automation");
// Careful profile - maximum realism, slower
testWithProfile(BehaviorProfile.CAREFUL, "Careful automation");
}
private static void testWithProfile(BehaviorProfile profile, String description) {
DriverConfig config = DriverConfig.builder()
.humanBehavior(true)
.behaviorProfile(profile)
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);
try {
System.out.println("Testing " + description);
long startTime = System.currentTimeMillis();
driver.get("https://example.com");
WebElement searchBox = driver.findElement(By.name("q"));
driver.humanType(searchBox, "test query");
WebElement button = driver.findElement(By.name("search"));
driver.humanClick(button);
long endTime = System.currentTimeMillis();
System.out.println("Completed in: " + (endTime - startTime) + "ms");
} finally {
driver.quit();
}
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
public class FingerprintExample {
public static void main(String[] args) throws InterruptedException {
DriverConfig config = DriverConfig.builder()
.randomizeFingerprint(true) // Enable fingerprint randomization
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);
try {
// Navigate to fingerprint testing site
driver.get("https://browserleaks.com/canvas");
Thread.sleep(3000);
// Take screenshot of first fingerprint
System.out.println("First fingerprint captured");
// Wait for fingerprint to change (randomization occurs periodically)
Thread.sleep(65000); // Wait just over 1 minute
// Refresh to see new fingerprint
driver.navigate().refresh();
Thread.sleep(3000);
System.out.println("Fingerprint should be different now");
} finally {
driver.quit();
}
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
public class ProxyExample {
public static void main(String[] args) {
// HTTP proxy
DriverConfig httpProxyConfig = DriverConfig.builder()
.proxy("http://proxy.example.com:8080")
.build();
// SOCKS proxy
DriverConfig socksProxyConfig = DriverConfig.builder()
.proxy("socks5://proxy.example.com:1080")
.build();
// Authenticated proxy
DriverConfig authProxyConfig = DriverConfig.builder()
.proxy("http://username:password@proxy.example.com:8080")
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(httpProxyConfig);
try {
driver.get("https://whatismyipaddress.com");
Thread.sleep(5000);
// IP should show proxy's IP address
} catch (Exception e) {
e.printStackTrace();
} finally {
driver.quit();
}
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
import org.openqa.selenium.OutputType;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class HeadlessExample {
public static void main(String[] args) {
DriverConfig config = DriverConfig.builder()
.headless(true) // Enable headless mode
.windowSize(1920, 1080) // Set virtual window size
.randomizeFingerprint(true) // Still randomize fingerprints
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);
try {
driver.get("https://example.com");
// Take screenshot in headless mode
File screenshot = driver.getScreenshotAs(OutputType.FILE);
Files.copy(screenshot.toPath(),
Paths.get("headless-screenshot.png"));
System.out.println("Screenshot saved!");
System.out.println("Page title: " + driver.getTitle());
} catch (Exception e) {
e.printStackTrace();
} finally {
driver.quit();
}
}
}import com.undetected.chromedriver.UndetectedChromeDriver;
import com.undetected.chromedriver.config.DriverConfig;
public class MobileEmulationExample {
public static void main(String[] args) {
DriverConfig config = DriverConfig.builder()
.mobileEmulation(true) // Enable mobile emulation
.userAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)")
.windowSize(375, 812) // iPhone X dimensions
.build();
UndetectedChromeDriver driver = new UndetectedChromeDriver(config);
try {
driver.get("https://m.example.com");
// Site should display mobile version
System.out.println("Mobile site loaded: " + driver.getTitle());
// Interact with mobile-specific elements
WebElement mobileMenu = driver.findElement(By.className("mobile-menu"));
driver.humanClick(mobileMenu);
} finally {
driver.quit();
}
}
}| Method | Description |
|---|---|
humanClick(WebElement element) |
Performs human-like click with mouse movement |
humanType(WebElement element, String text) |
Types text with realistic delays and typos |
humanScroll(int targetY) |
Smooth scrolling to Y coordinate |
humanScrollToElement(WebElement element) |
Scrolls element into view naturally |
performRandomActions() |
Simulates idle user behavior |
getBotDetectionHandler() |
Returns the bot detection handler |
getHumanBehavior() |
Returns the human behavior simulator |
getInstanceId() |
Returns unique instance identifier |
isActive() |
Checks if driver is still active |
| Option | Type | Default | Description |
|---|---|---|---|
headless |
boolean | false | Run in headless mode |
windowSize |
int, int | 1200x800 | Browser window dimensions |
userAgent |
String | Random | Custom user agent string |
proxy |
String | null | Proxy server URL |
humanBehavior |
boolean | false | Enable human behavior simulation |
randomizeFingerprint |
boolean | false | Enable fingerprint randomization |
behaviorProfile |
BehaviorProfile | NORMAL | Speed of human behavior |
implicitWaitMs |
int | 3000 | Implicit wait timeout |
pageLoadTimeoutMs |
int | 30000 | Page load timeout |
disableImages |
boolean | false | Disable image loading |
verboseLogging |
boolean | false | Enable verbose logging |
Always use try-finally or try-with-resources to ensure proper cleanup:
try (UndetectedChromeDriver driver = new UndetectedChromeDriver()) {
// Your automation code
} // Driver automatically quitsEnable human behavior for sites with advanced bot detection:
DriverConfig config = DriverConfig.builder()
.humanBehavior(true)
.behaviorProfile(BehaviorProfile.NORMAL)
.build();Always check for rate limiting before making requests:
if (driver.getBotDetectionHandler().isRateLimited()) {
int waitTime = driver.getBotDetectionHandler().getRecommendedWaitTime();
Thread.sleep(waitTime * 1000);
}Enable fingerprint randomization for long-running sessions:
DriverConfig config = DriverConfig.builder()
.randomizeFingerprint(true)
.build();Implement proper error handling for bot detection scenarios:
try {
driver.get(url);
if (driver.getBotDetectionHandler().isBotDetectionActive()) {
if (!driver.getBotDetectionHandler().handleBotDetection()) {
// Implement fallback strategy
}
}
} catch (Exception e) {
// Handle errors appropriately
}Problem: ChromeDriver not found at: /path/to/driver
Solution:
- Ensure Chrome browser is installed
- Clear WebDriverManager cache:
~/.cache/selenium - Enable force download:
.forceDriverDownload(true)
Problem: Still detected by anti-bot systems
Solution:
- Enable all anti-detection features
- Use CAREFUL behavior profile
- Add delays between actions
- Rotate proxies/user agents
Problem: Automation runs slowly
Solution:
- Use FAST behavior profile
- Disable image loading
- Reduce implicit wait times
- Use headless mode when possible
Problem: Memory usage increases over time
Solution:
- Always call
driver.quit() - Limit concurrent instances
- Monitor thread pool usage
- Implement periodic restarts
Enable verbose logging for troubleshooting:
DriverConfig config = DriverConfig.builder()
.verboseLogging(true)
.logFile("/path/to/debug.log")
.build();- Each driver instance uses ~100-200MB RAM
- Fingerprint randomization adds ~10MB overhead
- Human behavior simulation has minimal impact
- Stealth JavaScript execution: <1% CPU
- Human behavior simulation: 2-5% CPU during actions
- Fingerprint randomization: 1-2% CPU periodically
- No additional network requests
- Proxy usage may add latency
- Rate limiting checks are passive
- Use headless mode when UI not required
- Disable images for faster loading
- Adjust timeouts based on network speed
- Use appropriate behavior profiles
- Limit concurrent instances based on resources
We welcome contributions! Please see our Contributing Guide for details.
# Clone repository
git clone https://github.com/yourusername/undetected-chromedriver.git
# Build project
mvn clean install
# Run tests
mvn test- Follow Java naming conventions
- Add JavaDoc for public methods
- Include unit tests for new features
- Ensure thread safety
This project is licensed under the MIT License - see the LICENSE file for details.
- ultrafunkamsterdam/undetected-chromedriver - The original Python implementation that inspired this Java port
- Selenium WebDriver team for the excellent automation framework
- WebDriverManager for automatic driver management
- The open-source community for inspiration and contributions
Note: This library is for educational and testing purposes. Always respect website terms of service and use responsibly.