undetectedchromedrivergo

package module
v0.0.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2025 License: MIT Imports: 13 Imported by: 0

README

Undetected ChromeDriver for Go

English | 中文

A Selenium-based implementation of undetected-chromedriver for Go. This package helps bypass bot detection systems like Cloudflare, Distil Networks, and others by making ChromeDriver harder to detect.

Features

  • 🚀 Automatic ChromeDriver patching to remove detection signatures
  • 🔍 Bypasses common bot detection mechanisms
  • 🛠️ Simple API based on tebeka/selenium
  • 🎯 Removes CDP runtime properties that expose automation
  • 🌐 Cross-platform support (Linux, macOS, Windows)
  • ⚙️ Highly configurable with functional options

Installation

go get github.com/Flying-Tom/undetected-chromedriver-go

Quick Start

package main

import (
    "log"
    "time"
    
    ucg "github.com/Flying-Tom/undetected-chromedriver-go"
)

func main() {
    // Create Chrome driver
    driver, err := ucg.NewChromeDriver(
        ucg.WithDebug(),
    )
    if err != nil {
        log.Fatalf("Failed to create driver: %v", err)
    }
    defer driver.Quit()

    // Navigate to a website
    if err = driver.Get("https://nowsecure.nl"); err != nil {
        log.Fatalf("Failed to navigate: %v", err)
    }

    time.Sleep(10 * time.Second)
}

Configuration Options

The driver supports various configuration options through functional options:

driver, err := ucg.NewChromeDriver(
    ucg.WithDebug(),                          // Enable debug logging
    ucg.WithHeadless(),                       // Run in headless mode
    ucg.WithUserDataDir("/path/to/profile"),  // Set user data directory
    ucg.WithPort(9515),                       // Set ChromeDriver port
    ucg.WithVersion(120),                     // Specify Chrome version
    ucg.WithBrowserExecutable("/path/to/chrome"), // Custom Chrome binary
    ucg.WithDriverExecutable("/path/to/driver"),  // Custom ChromeDriver binary
    ucg.WithSuppressWelcome(),                // Suppress welcome screen
    ucg.WithSandbox(),                        // Enable sandbox (disabled by default)
    ucg.WithChromeArgs(                       // Additional Chrome arguments
        "--disable-blink-features=AutomationControlled",
    ),
)

Available Options

Option Description
WithDebug() Enable debug output
WithHeadless() Run browser in headless mode
WithUserDataDir(path) Set Chrome user data directory
WithPort(port) Set ChromeDriver port (default: auto-assign)
WithVersion(version) Specify Chrome major version (e.g., 120)
WithDriverExecutable(path) Path to custom ChromeDriver binary
WithBrowserExecutable(path) Path to custom Chrome binary
WithChromeArgs(...args) Additional Chrome command-line arguments
WithSuppressWelcome() Suppress Chrome welcome screen
WithSandbox() Enable Chrome sandbox (disabled by default)

How It Works

  1. Automatic Version Detection: Detects your installed Chrome version
  2. Driver Patching: Downloads and patches ChromeDriver to remove CDC (Chrome DevTools Protocol) signatures
  3. Runtime Property Removal: Removes automation-related JavaScript properties
  4. Stealth Configuration: Applies various arguments to make the browser appear more human-like

Advanced Example

package main

import (
    "log"
    "time"
    
    ucg "github.com/Flying-Tom/undetected-chromedriver-go"
    "github.com/tebeka/selenium"
)

func main() {
    driver, err := ucg.NewChromeDriver(
        ucg.WithDebug(),
        ucg.WithHeadless(),
        ucg.WithUserDataDir("/tmp/chrome-profile"),
        ucg.WithSuppressWelcome(),
        ucg.WithChromeArgs("--disable-blink-features=AutomationControlled"),
    )
    if err != nil {
        log.Fatalf("Failed to create driver: %v", err)
    }
    defer driver.Quit()

    // Navigate to bot detection test page
    if err = driver.Get("https://bot.sannysoft.com"); err != nil {
        log.Fatalf("Failed to navigate: %v", err)
    }

    time.Sleep(2 * time.Second)

    // Check if navigator.webdriver is properly hidden
    result, err := driver.ExecuteScript("return navigator.webdriver", nil)
    if err != nil {
        log.Printf("Failed to execute script: %v", err)
    } else {
        log.Printf("navigator.webdriver = %v", result)
    }

    // Get page title
    title, err := driver.Title()
    if err != nil {
        log.Printf("Failed to get title: %v", err)
    } else {
        log.Printf("Page title: %s", title)
    }

    // Find element
    elem, err := driver.FindElement(selenium.ByTagName, "body")
    if err != nil {
        log.Printf("Failed to find element: %v", err)
    } else {
        text, err := elem.Text()
        if err != nil {
            log.Printf("Failed to get text: %v", err)
        } else {
            log.Printf("Body text length: %d bytes", len(text))
        }
    }

    time.Sleep(10 * time.Second)
}

Requirements

  • Go 1.20 or higher
  • Google Chrome installed (or use the built-in installer - see below)
  • Internet connection (for downloading ChromeDriver)

Installing Google Chrome

If you don't have Google Chrome installed, you can use the built-in installer:

package main

import (
    "log"
    
    "github.com/Flying-Tom/undetected-chromedriver-go/installer"
)

func main() {
    chromeInstaller := installer.NewChromeInstaller()
    
    // Check if Chrome is installed
    if !chromeInstaller.IsInstalled() {
        log.Println("Installing Google Chrome...")
        if err := chromeInstaller.Install(); err != nil {
            log.Fatalf("Failed to install Chrome: %v", err)
        }
    }
    
        // Now you can use undetected-chromedriver
}

Note:

  • On Linux:
    • Supports multiple distributions (Debian/Ubuntu, Alpine, Arch, Fedora/RHEL/CentOS)
    • Automatically detects the distribution and uses the appropriate package manager
    • On Alpine and Arch, installs Chromium instead of Google Chrome
    • On Alpine Linux, also install chromium-chromedriver: apk add chromium-chromedriver
    • Requires sudo privileges for installation
  • On macOS, the installer will copy Chrome to /Applications
  • On Windows, the installer runs silently

Platform Support

  • ✅ Linux
    • Debian/Ubuntu (Google Chrome via .deb)
    • Alpine Linux (Chromium via apk) - Requires chromium-chromedriver package
    • Arch Linux (Chromium via pacman)
    • Fedora/RHEL/CentOS (Google Chrome via dnf/yum)
  • ✅ macOS (Google Chrome)
  • ✅ Windows (Google Chrome)

Important Note for Alpine Linux:

Alpine Linux uses musl libc instead of glibc, so the official ChromeDriver binaries from Google won't work. You must install chromium-chromedriver from the Alpine package repository:

apk add chromium chromium-chromedriver

The library will automatically detect Alpine Linux and use the system-installed chromedriver at /usr/bin/chromedriver.

Testing

# Run basic example
make run-basic

# Run advanced example
make run-advanced

# Run tests
go test ./...

Comparison with Python's undetected-chromedriver

This is a Go port inspired by ultrafunkamsterdam/undetected-chromedriver. Key differences:

  • Native Go implementation using tebeka/selenium
  • Functional options pattern for configuration
  • Cross-platform ChromeDriver patching
  • Automatic Chrome version detection

Troubleshooting

User data directory already in use
Error: session not created: probably user data directory is already in use, 
please specify a unique value for --user-data-dir argument, or don't use --user-data-dir

Cause: Multiple Chrome instances are trying to use the same user data directory, or a previous Chrome instance didn't shut down properly.

Solutions:

  1. Let the library auto-generate a unique directory (Recommended):

    driver, err := ucg.NewChromeDriver(
        // Don't use WithUserDataDir() - library will auto-generate unique temp dir
        ucg.WithHeadless(),
    )
    

    The library will automatically create a unique temporary directory for each instance and clean it up when Quit() is called.

  2. Use a unique directory for each instance:

    import (
        "fmt"
        "time"
    )
    
    userDataDir := fmt.Sprintf("/tmp/chrome-profile-%d", time.Now().UnixNano())
    driver, err := ucg.NewChromeDriver(
        ucg.WithUserDataDir(userDataDir),
    )
    
  3. Kill existing Chrome processes:

    # Linux/macOS
    pkill -f chrome
    
    # Windows
    taskkill /F /IM chrome.exe
    
  4. Always call Quit() in a defer statement:

    driver, err := ucg.NewChromeDriver()
    if err != nil {
        log.Fatal(err)
    }
    defer driver.Quit() // Ensures cleanup even if program crashes
    
Chrome not found
Error: failed to get chrome version

Solution: Make sure Google Chrome is installed in the default location.

ChromeDriver download fails
Error: download driver: unexpected status code: 404

Solution: Specify a valid Chrome version using WithVersion() option.

Permission denied on Linux/macOS
Error: failed to start chromedriver: permission denied

Solution: The patched driver should be executable. This is handled automatically.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Chrome

type Chrome struct {
	selenium.WebDriver
	// contains filtered or unexported fields
}

Chrome represents the undetected Chrome browser instance.

func NewChromeDriver

func NewChromeDriver(opts ...Option) (*Chrome, error)

NewChromeDriver creates a new undetected Chrome WebDriver.

func (*Chrome) Get

func (c *Chrome) Get(url string) error

Get navigates the browser to the provided URL.

func (*Chrome) Quit

func (c *Chrome) Quit() error

Quit closes the browser and cleans up resources.

type Config

type Config struct {
	// DriverExecutable can optionally be set to provide a custom driver.
	// If the driver is not patched yet it will be patched automatically.
	DriverExecutable string

	// BrowserExecutable path to chrome binary
	BrowserExecutable string

	// UserDataDir is the directory to use as chrome user profile
	UserDataDir string

	// Port is the port the chromedriver will listen on
	Port int

	// DebuggerAddress is the address the chrome debugger will listen on
	DebuggerAddress string

	// ChromeArgs are additional arguments to pass to chrome.
	ChromeArgs []string

	// DriverArgs are additional arguments to pass to the chromedriver.
	DriverArgs []string

	// Language locale to pass to chrome. e.g.'en-US'
	Language string

	// SuppressWelcome suppresses the welcome screen
	SuppressWelcome bool

	// KeepAlive keeps the browser alive after driver quits
	KeepAlive bool

	// LogLevel sets the log level (0-3)
	LogLevel int

	// Headless runs browser in headless mode
	Headless bool

	// Version is the main chromedriver version to use, e.g. 107.
	Version int

	// Debug enables debug mode
	Debug bool

	// Sandbox enables/disables sandbox
	Sandbox bool
}

Config for Chrome configuration.

func NewConfig

func NewConfig(opts ...Option) *Config

NewConfig creates new config object.

type Option

type Option func(*Config)

Option is a functional option type.

func WithBrowserExecutable

func WithBrowserExecutable(path string) Option

WithBrowserExecutable sets the browser executable path.

func WithChromeArgs

func WithChromeArgs(args ...string) Option

WithChromeArgs sets additional chrome arguments.

func WithDebug

func WithDebug() Option

WithDebug sets the debug option.

func WithDriverExecutable

func WithDriverExecutable(path string) Option

WithDriverExecutable sets the driver executable path.

func WithHeadless

func WithHeadless() Option

WithHeadless sets headless mode.

func WithPort

func WithPort(port int) Option

WithPort sets the chromedriver port.

func WithSandbox

func WithSandbox() Option

WithSandbox enables the sandbox.

func WithSuppressWelcome

func WithSuppressWelcome() Option

WithSuppressWelcome suppresses the welcome screen.

func WithUserDataDir

func WithUserDataDir(path string) Option

WithUserDataDir sets a directory to use as chrome user profile.

func WithVersion

func WithVersion(version int) Option

WithVersion sets the chrome version.

Directories

Path Synopsis
examples
advanced command
basic command
install-chrome command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL