Chrome DevTools Protocol version 115 bindings for Selenium Java WebDriver enabling programmatic browser debugging capabilities
—
Browser target (tab/window) management, debugging session control, and multi-target coordination with attachment and detachment capabilities through the v115Target class.
Comprehensive target management for controlling browser tabs, windows, and debugging sessions.
/**
* Target domain for browser target and session management
* Implements the idealized Target interface for version independence
*/
public class v115Target implements Target {
/**
* Detach from a specific target or session
* @param sessionId Optional session ID to detach from
* @param targetId Optional target ID to detach from
* @return Command to detach from target
*/
public Command<Void> detachFromTarget(Optional<SessionID> sessionId, Optional<TargetID> targetId);
/**
* Get list of all available targets
* @return Command returning list of TargetInfo objects
*/
public Command<List<TargetInfo>> getTargets();
/**
* Attach to a target for debugging
* @param targetId Target ID to attach to
* @return Command returning SessionID for the debugging session
*/
public Command<SessionID> attachToTarget(TargetID targetId);
/**
* Set automatic attachment behavior for new targets
* @return Command to enable auto-attach for new targets
*/
public Command<Void> setAutoAttach();
/**
* Get target detached event stream
* @return Event stream for target detachment notifications
*/
public Event<TargetID> detached();
}Discover and enumerate all browser targets including tabs, service workers, and other contexts.
Usage Examples:
import org.openqa.selenium.devtools.v115.v115Target;
import org.openqa.selenium.devtools.idealized.target.model.TargetInfo;
import org.openqa.selenium.devtools.idealized.target.model.TargetID;
// Create target domain
v115Target target = new v115Target();
// Get all available targets
List<TargetInfo> targets = devTools.send(target.getTargets());
System.out.println("Found " + targets.size() + " targets:");
for (TargetInfo targetInfo : targets) {
System.out.println("Target ID: " + targetInfo.getTargetId());
System.out.println(" Type: " + targetInfo.getType());
System.out.println(" Title: " + targetInfo.getTitle());
System.out.println(" URL: " + targetInfo.getUrl());
System.out.println(" Attached: " + targetInfo.getAttached());
if (targetInfo.getOpenerId().isPresent()) {
System.out.println(" Opener: " + targetInfo.getOpenerId().get());
}
if (targetInfo.getBrowserContextId().isPresent()) {
System.out.println(" Context: " + targetInfo.getBrowserContextId().get());
}
System.out.println();
}Attach to specific targets for debugging and control multiple browser contexts.
Usage Examples:
import org.openqa.selenium.devtools.idealized.target.model.SessionID;
// Find target to attach to (e.g., a specific tab)
List<TargetInfo> targets = devTools.send(target.getTargets());
Optional<TargetInfo> pageTarget = targets.stream()
.filter(t -> "page".equals(t.getType()))
.filter(t -> t.getUrl().contains("example.com"))
.findFirst();
if (pageTarget.isPresent()) {
TargetID targetId = pageTarget.get().getTargetId();
// Attach to the target
SessionID sessionId = devTools.send(target.attachToTarget(targetId));
System.out.println("Attached to target with session: " + sessionId);
// Use the session for target-specific operations
// Note: Attached sessions can be used with DevTools.send() by specifying sessionId
// Detach when done
devTools.send(target.detachFromTarget(Optional.of(sessionId), Optional.empty()));
System.out.println("Detached from target");
}Coordinate operations across multiple browser targets simultaneously.
Usage Examples:
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// Set up multi-target management
Map<TargetID, SessionID> attachedTargets = new HashMap<>();
ExecutorService executor = Executors.newCachedThreadPool();
// Get all page targets
List<TargetInfo> pageTargets = devTools.send(target.getTargets()).stream()
.filter(t -> "page".equals(t.getType()))
.toList();
// Attach to all page targets
List<CompletableFuture<Void>> attachTasks = pageTargets.stream()
.map(targetInfo -> CompletableFuture.runAsync(() -> {
try {
TargetID targetId = targetInfo.getTargetId();
SessionID sessionId = devTools.send(target.attachToTarget(targetId));
synchronized (attachedTargets) {
attachedTargets.put(targetId, sessionId);
}
System.out.println("Attached to target: " + targetInfo.getTitle());
} catch (Exception e) {
System.err.println("Failed to attach to target: " + e.getMessage());
}
}, executor))
.toList();
// Wait for all attachments to complete
CompletableFuture.allOf(attachTasks.toArray(new CompletableFuture[0]))
.join();
System.out.println("Attached to " + attachedTargets.size() + " targets");
// Perform operations on all attached targets
attachedTargets.forEach((targetId, sessionId) -> {
try {
// Example: Enable runtime on each target
devTools.send(
org.openqa.selenium.devtools.v115.runtime.Runtime.enable(),
sessionId
);
} catch (Exception e) {
System.err.println("Error enabling runtime on target " + targetId + ": " + e.getMessage());
}
});
// Clean up - detach from all targets
attachedTargets.forEach((targetId, sessionId) -> {
try {
devTools.send(target.detachFromTarget(Optional.of(sessionId), Optional.empty()));
} catch (Exception e) {
System.err.println("Error detaching from target " + targetId + ": " + e.getMessage());
}
});
executor.shutdown();Configure automatic attachment to new targets as they are created.
Usage Examples:
// Enable auto-attach for new targets
devTools.send(target.setAutoAttach());
// Listen for target detachment events
devTools.addListener(target.detached(), detachedTargetId -> {
System.out.println("Target detached: " + detachedTargetId);
// Clean up any tracking for this target
synchronized (attachedTargets) {
SessionID sessionId = attachedTargets.remove(detachedTargetId);
if (sessionId != null) {
System.out.println("Cleaned up session: " + sessionId);
}
}
});
// Open new tabs - they will be automatically attached
driver.executeScript("window.open('https://example.com/page1', '_blank');");
driver.executeScript("window.open('https://example.com/page2', '_blank');");
// Give some time for auto-attachment
Thread.sleep(1000);
// Check attached targets
List<TargetInfo> currentTargets = devTools.send(target.getTargets());
long attachedCount = currentTargets.stream()
.filter(TargetInfo::getAttached)
.count();
System.out.println("Currently attached to " + attachedCount + " targets");Monitor target lifecycle events for dynamic target management.
Usage Examples:
import org.openqa.selenium.devtools.v115.target.Target;
import org.openqa.selenium.devtools.v115.target.model.TargetInfo;
// Listen for target creation events
devTools.addListener(Target.targetCreated(), targetInfo -> {
System.out.println("New target created:");
System.out.println(" ID: " + targetInfo.getTargetId());
System.out.println(" Type: " + targetInfo.getType());
System.out.println(" URL: " + targetInfo.getUrl());
// Auto-attach to new page targets
if ("page".equals(targetInfo.getType())) {
try {
SessionID sessionId = devTools.send(target.attachToTarget(targetInfo.getTargetId()));
System.out.println(" Auto-attached with session: " + sessionId);
} catch (Exception e) {
System.err.println(" Failed to auto-attach: " + e.getMessage());
}
}
});
// Listen for target info changes
devTools.addListener(Target.targetInfoChanged(), targetInfo -> {
System.out.println("Target info updated:");
System.out.println(" ID: " + targetInfo.getTargetId());
System.out.println(" New Title: " + targetInfo.getTitle());
System.out.println(" New URL: " + targetInfo.getUrl());
});
// Listen for target destruction
devTools.addListener(Target.targetDestroyed(), targetId -> {
System.out.println("Target destroyed: " + targetId);
});
// Enable target domain for events
devTools.send(Target.setDiscoverTargets(true));Execute DevTools commands on specific targets using session IDs:
// Attach to a specific target
TargetID specificTarget = findTargetByUrl("https://api.example.com");
SessionID apiSession = devTools.send(target.attachToTarget(specificTarget));
// Execute commands on the specific target
devTools.send(
org.openqa.selenium.devtools.v115.runtime.Runtime.enable(),
apiSession
);
devTools.send(
org.openqa.selenium.devtools.v115.runtime.Runtime.evaluate(
"console.log('Hello from API target');",
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty()
),
apiSession
);Set up communication between different browser targets:
// Set up cross-target messaging system
Map<TargetID, SessionID> messagingTargets = new HashMap<>();
// Attach to all page targets
devTools.send(target.getTargets()).stream()
.filter(t -> "page".equals(t.getType()))
.forEach(targetInfo -> {
try {
SessionID sessionId = devTools.send(target.attachToTarget(targetInfo.getTargetId()));
messagingTargets.put(targetInfo.getTargetId(), sessionId);
// Set up message listener on each target
devTools.send(
org.openqa.selenium.devtools.v115.runtime.Runtime.addBinding(
"crossTargetMessage",
Optional.empty(),
Optional.empty()
),
sessionId
);
} catch (Exception e) {
System.err.println("Failed to set up messaging for target: " + e.getMessage());
}
});
// Handle cross-target messages
devTools.addListener(
org.openqa.selenium.devtools.v115.runtime.Runtime.bindingCalled(),
bindingEvent -> {
if ("crossTargetMessage".equals(bindingEvent.getName())) {
String message = bindingEvent.getPayload();
System.out.println("Cross-target message: " + message);
// Broadcast to all other targets
messagingTargets.values().forEach(sessionId -> {
try {
devTools.send(
org.openqa.selenium.devtools.v115.runtime.Runtime.evaluate(
"console.log('Received cross-target message: " + message + "');",
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty(),
Optional.empty()
),
sessionId
);
} catch (Exception e) {
System.err.println("Failed to broadcast message: " + e.getMessage());
}
});
}
}
);Track and manage resources across multiple targets:
// Track target resources
Map<TargetID, TargetResources> targetResources = new ConcurrentHashMap<>();
class TargetResources {
private final SessionID sessionId;
private final Set<String> enabledDomains = ConcurrentHashMap.newKeySet();
private final List<String> injectedScripts = new ArrayList<>();
public TargetResources(SessionID sessionId) {
this.sessionId = sessionId;
}
public void enableDomain(String domain) {
enabledDomains.add(domain);
}
public void addScript(String script) {
injectedScripts.add(script);
}
public void cleanup() {
// Clean up resources for this target
System.out.println("Cleaning up " + enabledDomains.size() + " domains and " +
injectedScripts.size() + " scripts");
}
}
// Set up resource tracking
devTools.addListener(target.detached(), detachedTargetId -> {
TargetResources resources = targetResources.remove(detachedTargetId);
if (resources != null) {
resources.cleanup();
}
});Handle cases where target attachment fails:
try {
SessionID sessionId = devTools.send(target.attachToTarget(targetId));
System.out.println("Successfully attached to target");
} catch (Exception e) {
System.err.println("Failed to attach to target: " + e.getMessage());
// Check if target still exists
List<TargetInfo> currentTargets = devTools.send(target.getTargets());
boolean targetExists = currentTargets.stream()
.anyMatch(t -> t.getTargetId().equals(targetId));
if (!targetExists) {
System.err.println("Target no longer exists");
} else {
System.err.println("Target exists but attachment failed - may already be attached");
}
}Handle session lifecycle errors gracefully:
// Track active sessions for cleanup
Set<SessionID> activeSessions = ConcurrentHashMap.newKeySet();
// Safe session cleanup
public void cleanupSession(SessionID sessionId) {
if (activeSessions.contains(sessionId)) {
try {
devTools.send(target.detachFromTarget(Optional.of(sessionId), Optional.empty()));
activeSessions.remove(sessionId);
System.out.println("Successfully cleaned up session: " + sessionId);
} catch (Exception e) {
System.err.println("Error cleaning up session " + sessionId + ": " + e.getMessage());
// Remove from tracking even if cleanup failed
activeSessions.remove(sessionId);
}
}
}
// Cleanup all sessions on shutdown
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Cleaning up " + activeSessions.size() + " active sessions");
activeSessions.forEach(this::cleanupSession);
}));Handle target enumeration failures:
try {
List<TargetInfo> targets = devTools.send(target.getTargets());
System.out.println("Found " + targets.size() + " targets");
} catch (Exception e) {
System.err.println("Failed to get target list: " + e.getMessage());
// Fallback to basic target operations
System.out.println("Falling back to current target only");
}Install with Tessl CLI
npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-devtools-v115