Common Scenarios
This guide demonstrates common browser automation scenarios using WebDriverBiDi.NET.
Basic Page Navigation
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
// Get the active context
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
string contextId = tree.ContextTree[0].BrowsingContextId;
// Navigate and wait for page load
NavigateCommandParameters navParams = new NavigateCommandParameters(
contextId,
"https://example.com")
{
Wait = ReadinessState.Complete
};
NavigateCommandResult result = await driver.BrowsingContext.NavigateAsync(navParams);
Console.WriteLine($"Navigated to: {result.Url}");
}
catch (WebDriverBiDiTimeoutException ex)
{
Console.WriteLine($"Navigation timeout: {ex.Message}");
// Handle timeout - maybe retry or fail gracefully
}
catch (WebDriverBiDiException ex)
{
Console.WriteLine($"Navigation failed: {ex.Message}");
// Handle other protocol errors
}
finally
{
await driver.StopAsync();
}
Form Submission
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
string contextId = tree.ContextTree[0].BrowsingContextId;
// Navigate to form page
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com/form")
{ Wait = ReadinessState.Complete });
// Find the input field
string findInputScript = "document.querySelector('input[name=\"username\"]')";
EvaluateResult inputResult = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(findInputScript, new ContextTarget(contextId), true));
if (inputResult is EvaluateResultSuccess inputSuccess &&
inputSuccess.Result is NodeRemoteValue inputElement)
{
// Click the input to focus it
PerformActionsCommandParameters clickParams = new PerformActionsCommandParameters(contextId);
PointerSourceActions clickParamsMouse = new PointerSourceActions
{
Parameters = new PointerParameters { PointerType = PointerType.Mouse },
};
clickParamsMouse.Actions.Add(new PointerMoveAction
{
X = 0,
Y = 0,
Origin = Origin.Element(inputElement.ToSharedReference()),
});
clickParamsMouse.Actions.Add(new PointerDownAction(0));
clickParamsMouse.Actions.Add(new PointerUpAction(0));
clickParams.Actions.Add(clickParamsMouse);
await driver.Input.PerformActionsAsync(clickParams);
// Type into the field
string username = "testuser";
PerformActionsCommandParameters typeParams = new PerformActionsCommandParameters(contextId);
KeySourceActions typeParamsKeyboard = new KeySourceActions();
foreach (char c in username)
{
typeParamsKeyboard.Actions.Add(new KeyDownAction(c.ToString()));
typeParamsKeyboard.Actions.Add(new KeyUpAction(c.ToString()));
}
typeParams.Actions.Add(typeParamsKeyboard);
await driver.Input.PerformActionsAsync(typeParams);
// Submit the form by pressing Enter (WebDriver key code \uE007)
PerformActionsCommandParameters submitParams = new PerformActionsCommandParameters(contextId);
KeySourceActions submitKey = new KeySourceActions();
submitKey.Actions.Add(new KeyDownAction("\uE007"));
submitKey.Actions.Add(new KeyUpAction("\uE007"));
submitParams.Actions.Add(submitKey);
await driver.Input.PerformActionsAsync(submitParams);
}
}
finally
{
await driver.StopAsync();
}
Monitoring Console Logs
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
// Set up log monitoring with error handling inside the handler
List<string> consoleMessages = new List<string>();
driver.Log.OnEntryAdded.AddObserver((EntryAddedEventArgs e) =>
{
try
{
string message = $"[{e.Timestamp:HH:mm:ss}] {e.Level}: {e.Text}";
consoleMessages.Add(message);
Console.WriteLine(message);
}
catch (Exception ex)
{
// Handle errors within the event handler
Console.WriteLine($"Error processing log entry: {ex.Message}");
}
});
// Subscribe to log events
SubscribeCommandParameters subscribe =
new SubscribeCommandParameters(driver.Log.OnEntryAdded.EventName);
await driver.Session.SubscribeAsync(subscribe);
// Navigate to page
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
string contextId = tree.ContextTree[0].BrowsingContextId;
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com")
{ Wait = ReadinessState.Complete });
// Wait for logs to arrive
await Task.Delay(2000);
Console.WriteLine($"\nTotal console messages: {consoleMessages.Count}");
}
catch (WebDriverBiDiException ex)
{
Console.WriteLine($"WebDriver BiDi error: {ex.Message}");
}
finally
{
await driver.StopAsync();
}
Capturing Screenshots
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
string contextId = tree.ContextTree[0].BrowsingContextId;
// Navigate to page
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com")
{ Wait = ReadinessState.Complete });
// Capture full page screenshot
CaptureScreenshotCommandParameters screenshotParams =
new CaptureScreenshotCommandParameters(contextId);
CaptureScreenshotCommandResult result =
await driver.BrowsingContext.CaptureScreenshotAsync(screenshotParams);
// Save to file
byte[] imageBytes = Convert.FromBase64String(result.Data);
await File.WriteAllBytesAsync("screenshot.png", imageBytes);
Console.WriteLine("Screenshot saved to screenshot.png");
}
finally
{
await driver.StopAsync();
}
Network Traffic Monitoring
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
// Track all network requests
List<RequestData> requests = new List<RequestData>();
driver.Network.OnResponseCompleted.AddObserver((ResponseCompletedEventArgs e) =>
{
requests.Add(e.Request);
Console.WriteLine($"{e.Response.Status} - {e.Request.Method} {e.Request.Url}");
});
// Subscribe to network events
SubscribeCommandParameters subscribe =
new SubscribeCommandParameters(driver.Network.OnResponseCompleted.EventName);
await driver.Session.SubscribeAsync(subscribe);
// Navigate
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
string contextId = tree.ContextTree[0].BrowsingContextId;
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com")
{ Wait = ReadinessState.Complete });
// Wait for all resources to load
await Task.Delay(2000);
Console.WriteLine($"\nTotal requests: {requests.Count}");
// Analyze requests
int htmlCount = requests.Count(r => r.Url.Contains(".html") || r.Url.EndsWith("/"));
int cssCount = requests.Count(r => r.Url.Contains(".css"));
int jsCount = requests.Count(r => r.Url.Contains(".js"));
int imageCount = requests.Count(r => r.Url.Contains(".jpg") || r.Url.Contains(".png") || r.Url.Contains(".gif"));
Console.WriteLine($"HTML: {htmlCount}, CSS: {cssCount}, JS: {jsCount}, Images: {imageCount}");
}
finally
{
await driver.StopAsync();
}
To capture each request together with its response and bodies, or to save the traffic as a HAR file, see NetworkTrafficMonitor in Dramaturge.
Multi-Tab Management
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
// Create multiple tabs
List<string> tabIds = new List<string>();
for (int i = 0; i < 3; i++)
{
CreateCommandResult result = await driver.BrowsingContext.CreateAsync(
new CreateCommandParameters(CreateType.Tab));
tabIds.Add(result.BrowsingContextId);
Console.WriteLine($"Created tab {i + 1}: {result.BrowsingContextId}");
}
// Navigate each tab to different URL
string[] urls =
{
"https://example.com",
"https://example.org",
"https://example.net"
};
for (int i = 0; i < tabIds.Count; i++)
{
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(tabIds[i], urls[i])
{ Wait = ReadinessState.Complete });
Console.WriteLine($"Tab {i + 1} navigated to {urls[i]}");
}
// Get page titles from all tabs
for (int i = 0; i < tabIds.Count; i++)
{
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
"document.title",
new ContextTarget(tabIds[i]),
true));
if (result is EvaluateResultSuccess success &&
success.Result is StringRemoteValue stringValue)
{
string title = stringValue.Value ?? "No title";
Console.WriteLine($"Tab {i + 1} title: {title}");
}
}
// Close all tabs
foreach (string tabId in tabIds)
{
await driver.BrowsingContext.CloseAsync(new CloseCommandParameters(tabId));
}
Console.WriteLine("All tabs closed");
}
finally
{
await driver.StopAsync();
}
Waiting for Elements
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
string contextId = tree.ContextTree[0].BrowsingContextId;
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com")
{ Wait = ReadinessState.Complete });
// Wait for element to appear (with polling)
bool elementFound = false;
int maxAttempts = 30;
int attempt = 0;
while (!elementFound && attempt < maxAttempts)
{
EvaluateResult result = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(
"document.querySelector('.dynamic-content') !== null",
new ContextTarget(contextId),
true));
if (result is EvaluateResultSuccess success &&
success.Result is BooleanRemoteValue boolValue)
{
elementFound = boolValue.Value;
if (elementFound)
{
Console.WriteLine($"Element found after {attempt * 100}ms");
break;
}
}
await Task.Delay(100);
attempt++;
}
if (!elementFound)
{
Console.WriteLine("Element not found after timeout");
}
}
finally
{
await driver.StopAsync();
}
Cookie Management
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
string contextId = tree.ContextTree[0].BrowsingContextId;
// Set a cookie before navigating
PartialCookie cookie = new PartialCookie(
"userPreference",
BytesValue.FromString("darkMode"),
"example.com")
{
Path = "/",
Secure = false,
HttpOnly = false
};
await driver.Storage.SetCookieAsync(new SetCookieCommandParameters(cookie));
Console.WriteLine("Cookie set");
// Navigate
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com")
{ Wait = ReadinessState.Complete });
// Retrieve cookies
GetCookiesCommandParameters getCookiesParams = new GetCookiesCommandParameters();
getCookiesParams.Partition = new BrowsingContextPartitionDescriptor(contextId);
GetCookiesCommandResult cookies = await driver.Storage.GetCookiesAsync(getCookiesParams);
Console.WriteLine($"\nAll cookies ({cookies.Cookies.Count}):");
foreach (Cookie c in cookies.Cookies)
{
Console.WriteLine($" {c.Name} = {c.Value.Value}");
}
// Delete specific cookie
DeleteCookiesCommandParameters deleteParams = new DeleteCookiesCommandParameters();
deleteParams.Filter = new CookieFilter { Name = "userPreference" };
await driver.Storage.DeleteCookiesAsync(deleteParams);
Console.WriteLine("\nCookie deleted");
}
finally
{
await driver.StopAsync();
}
JavaScript Execution
BiDiDriver driver = new BiDiDriver(TimeSpan.FromSeconds(10));
await driver.StartAsync("ws://localhost:9515/session/YOUR-SESSION-ID");
try
{
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
string contextId = tree.ContextTree[0].BrowsingContextId;
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, "https://example.com")
{ Wait = ReadinessState.Complete });
// Execute simple expression
EvaluateResult titleResult = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters("document.title", new ContextTarget(contextId), true));
if (titleResult is EvaluateResultSuccess titleSuccess &&
titleSuccess.Result is StringRemoteValue titleValue)
{
Console.WriteLine($"Page title: {titleValue.Value}");
}
// Call function with arguments
string addFunction = "(a, b) => a + b";
CallFunctionCommandParameters funcParams = new CallFunctionCommandParameters(
addFunction,
new ContextTarget(contextId),
true);
funcParams.Arguments.Add(LocalValue.Number(10));
funcParams.Arguments.Add(LocalValue.Number(20));
EvaluateResult sumResult = await driver.Script.CallFunctionAsync(funcParams);
if (sumResult is EvaluateResultSuccess sumSuccess &&
sumSuccess.Result is NumberRemoteValue sumValue)
{
Console.WriteLine($"10 + 20 = {sumValue.Value}");
}
// Execute complex script
// Parenthesized: a script beginning with a brace parses as a block, not an object literal.
string complexScript = @"
({
url: window.location.href,
linkCount: document.querySelectorAll('a').length,
imageCount: document.querySelectorAll('img').length,
hasTitle: !!document.title
})";
EvaluateResult complexResult = await driver.Script.EvaluateAsync(
new EvaluateCommandParameters(complexScript, new ContextTarget(contextId), true));
if (complexResult is EvaluateResultSuccess complexSuccess &&
complexSuccess.Result.As<KeyValuePairCollectionRemoteValue>().Value is RemoteValueDictionary data)
{
Console.WriteLine($"\nPage analysis:");
Console.WriteLine($" URL: {data["url"].As<StringRemoteValue>().Value}");
Console.WriteLine($" Links: {data["linkCount"].As<NumberRemoteValue>().Value}");
Console.WriteLine($" Images: {data["imageCount"].As<NumberRemoteValue>().Value}");
Console.WriteLine($" Has title: {data["hasTitle"].As<BooleanRemoteValue>().Value}");
}
}
finally
{
await driver.StopAsync();
}
Next Steps
- Form Submission Example: Detailed form interaction
- Network Interception Example: Advanced network control
- Console Monitoring Example: Log collection patterns
- Preload Scripts Example: JavaScript injection