Skip to main content
Version: Latest

Headless Configuration Guide

Overviewโ€‹

Starting with Brobot 1.1.0, headless mode is explicitly configured via properties rather than auto-detected. This simplifies the codebase and avoids issues with Java's unreliable GraphicsEnvironment.isHeadless() detection, particularly on Windows systems.

Configurationโ€‹

Setting Headless Modeโ€‹

Headless mode must be explicitly configured via properties:

# application.properties
# Explicitly set headless mode (default: false)
brobot.headless=false

Property Valuesโ€‹

ValueDescriptionUse Case
false (default)GUI is availableNormal desktop environments, Windows/Mac/Linux with displays
trueNo display availableCI/CD pipelines, headless servers, Docker containers, test environments

How It Worksโ€‹

Simple Configuration-Based Approachโ€‹

The HeadlessDetector component simply reads the configured property value:

@Component
public class HeadlessDetector {

public HeadlessDetector(@Value("${brobot.headless:false}") boolean brobotHeadless) {
// Uses configured value ONLY - no auto-detection
this.headlessMode = brobotHeadless;
}

public boolean isHeadless() {
return headlessMode; // Returns configured value
}
}

No More Complex Workaroundsโ€‹

Previous versions attempted various workarounds for headless detection issues. These have been removed in favor of the simpler approach:

  • โŒ Removed: ForceNonHeadlessInitializer
  • โŒ Removed: RobotForcedInitializer
  • โŒ Removed: Direct Robot manipulation
  • โœ… Kept: Simple property-based configuration

Common Scenariosโ€‹

Desktop Development (Windows/Mac/Linux)โ€‹

# Default configuration - no changes needed
# brobot.headless defaults to false

CI/CD Pipeline (GitHub Actions, Jenkins)โ€‹

# application-ci.properties
brobot.headless=true
brobot.mock=true # Also enable mock mode for testing

Docker Containerโ€‹

# application-docker.properties
brobot.headless=true
brobot.mock=true

WSL2 Developmentโ€‹

# WSL2 with WSLg (GUI support)
brobot.headless=false

# WSL2 without display
brobot.headless=true

Why We Changedโ€‹

The Problem with Auto-Detectionโ€‹

Java's GraphicsEnvironment.isHeadless() has several issues:

  1. Cached Results: Once called, the result is cached and cannot change
  2. Gradle Interference: Gradle often sets java.awt.headless=true before the JVM starts
  3. Timing Issues: Early initialization can lock in the wrong headless state
  4. Platform Inconsistency: Different behavior on different operating systems

The Solution: Explicit Configurationโ€‹

By using explicit configuration:

  • Predictable: You know exactly what mode you're in
  • Simple: No complex detection logic or workarounds
  • Reliable: Works consistently across all platforms
  • Testable: Easy to test both modes

Troubleshootingโ€‹

Issue: Getting HeadlessExceptionโ€‹

Symptom: HeadlessException when running automation

Solution:

  1. Ensure brobot.headless=false in your properties
  2. If using Gradle, add to gradle.properties:
    org.gradle.jvmargs=-Djava.awt.headless=false

Issue: Click Actions Not Workingโ€‹

Symptom: Images are found but clicks fail

Solution:

  • This is likely a headless detection issue
  • Ensure brobot.headless=false is set
  • The click action now uses SikuliX directly, which handles Robot initialization lazily

Issue: Different Behavior in Testsโ€‹

Symptom: Tests behave differently than production

Solution: Ensure consistent configuration:

// In tests, extend BrobotTestBase
public class MyTest extends BrobotTestBase {
// Mock mode is automatically enabled
// Headless-safe testing environment
}

Best Practicesโ€‹

  1. Always set explicitly for production: Don't rely on defaults

    brobot.headless=false  # Explicitly set for your environment
  2. Use profiles for different environments:

    # application-dev.properties
    brobot.headless=false

    # application-ci.properties
    brobot.headless=true
  3. Use HeadlessDetector, not GraphicsEnvironment:

    // Good
    @Autowired
    private HeadlessDetector headlessDetector;

    if (headlessDetector.isHeadless()) { }

    // Avoid - unreliable
    if (GraphicsEnvironment.isHeadless()) { }

Mock Modeโ€‹

Mock mode (simulated actions) is separate from headless mode:

  • Mock mode: brobot.mock=true - Simulates actions for testing
  • Headless mode: brobot.headless=true - No display available

Both can be used together for CI/CD testing.

Screen Captureโ€‹

When brobot.headless=true, ensure appropriate capture provider:

brobot.capture.provider=MOCK  # Use mock provider for headless

Summaryโ€‹

  • Headless mode is explicitly configured via brobot.headless property
  • Auto-detection has been removed for simplicity and reliability
  • Default is false (assumes display is available)
  • No more complex workarounds or Robot initialization tricks
  • SikuliX handles all low-level details automatically