Browsing Context Module
The Browsing Context module provides functionality for managing browser tabs, windows, and iframes, as well as navigating and interacting with pages.
Overview
A browsing context represents a document environment in the browser. This can be:
- A browser tab
- A browser window
- An iframe within a page
Each browsing context has a unique identifier used to target operations.
Accessing the Module
BrowsingContextModule browsingContext = driver.BrowsingContext;
Timeout and Cancellation
All commands in this module accept optional timeoutOverride and CancellationToken parameters. Use timeoutOverride to set a per-command timeout (defaults to BiDiDriver.DefaultCommandTimeout when omitted). Use CancellationToken for cooperative cancellation. The Navigation with Timeout section below shows an example for NavigateAsync; the same parameters apply to all other commands (e.g., ActivateAsync, CaptureScreenshotAsync, CreateAsync). See the API Design Guide for more examples.
Getting Browsing Contexts
Get All Contexts
GetTreeCommandParameters parameters = new GetTreeCommandParameters();
GetTreeCommandResult result = await driver.BrowsingContext.GetTreeAsync(parameters);
foreach (BrowsingContextInfo context in result.ContextTree)
{
Console.WriteLine($"Context ID: {context.BrowsingContextId}");
Console.WriteLine($"URL: {context.Url}");
Console.WriteLine($"Parent: {context.Parent ?? "none"}");
Console.WriteLine($"Children: {context.Children?.Count ?? 0}");
}
Get Specific Context
GetTreeCommandParameters parameters = new GetTreeCommandParameters()
{
RootBrowsingContextId = contextId // Only get this context and its descendants
};
GetTreeCommandResult result = await driver.BrowsingContext.GetTreeAsync(parameters);
Get Only Top-Level Contexts
GetTreeCommandParameters parameters = new GetTreeCommandParameters()
{
MaxDepth = 0 // Don't include child contexts (iframes)
};
GetTreeCommandResult result = await driver.BrowsingContext.GetTreeAsync(parameters);
Creating Contexts
Create a New Tab
CreateCommandParameters parameters = new CreateCommandParameters(CreateType.Tab);
CreateCommandResult result = await driver.BrowsingContext.CreateAsync(parameters);
string newTabId = result.BrowsingContextId;
Console.WriteLine($"Created tab: {newTabId}");
Create a New Window
CreateCommandParameters parameters = new CreateCommandParameters(CreateType.Window);
CreateCommandResult result = await driver.BrowsingContext.CreateAsync(parameters);
string newWindowId = result.BrowsingContextId;
Create Context in User Context
CreateUserContextCommandResult userContext =
await driver.Browser.CreateUserContextAsync(new CreateUserContextCommandParameters());
CreateCommandParameters @params = new CreateCommandParameters(CreateType.Tab)
{
UserContextId = userContext.UserContextId
};
CreateCommandResult result = await driver.BrowsingContext.CreateAsync(@params);
Navigation
Basic Navigation
NavigateCommandParameters parameters = new NavigateCommandParameters(
contextId,
"https://example.com");
NavigateCommandResult result = await driver.BrowsingContext.NavigateAsync(parameters);
Console.WriteLine($"Navigation ID: {result.NavigationId}");
Console.WriteLine($"URL: {result.Url}");
Wait for Page Load
NavigateCommandParameters parameters = new NavigateCommandParameters(
contextId,
"https://example.com")
{
Wait = ReadinessState.Complete // Wait for full page load
};
await driver.BrowsingContext.NavigateAsync(parameters);
Readiness states:
ReadinessState.None: Return once the navigation is committed, without waiting for the document to loadReadinessState.Interactive: Wait for DOM readyReadinessState.Complete: Wait for full page load (including images, CSS)
Navigation with Timeout
Use the timeoutOverride parameter (second argument to NavigateAsync) to fail fast when a page takes too long to load:
NavigateCommandParameters parameters = new NavigateCommandParameters(
contextId,
"https://example.com")
{
Wait = ReadinessState.Complete
};
await driver.BrowsingContext.NavigateAsync(
parameters,
TimeSpan.FromSeconds(30)); // Fail if not loaded in 30 seconds
Traversing History
Use TraverseHistoryAsync to navigate back or forward in the browser history. The method takes a TraverseHistoryCommandParameters object with the browsing context ID and a delta value: negative for back, positive for forward. The method returns TraverseHistoryCommandResult (an empty result indicating success).
Back/Forward Navigation
Reload Page
ReloadCommandParameters parameters = new ReloadCommandParameters(contextId);
await driver.BrowsingContext.ReloadAsync(parameters);
// Or wait for complete reload
ReloadCommandParameters reloadParams = new ReloadCommandParameters(contextId)
{
Wait = ReadinessState.Complete
};
await driver.BrowsingContext.ReloadAsync(reloadParams);
Closing Contexts
Close a Tab
CloseCommandParameters parameters = new CloseCommandParameters(contextId);
await driver.BrowsingContext.CloseAsync(parameters);
Close All Tabs in User Context
// Get all contexts in user context
GetTreeCommandResult tree = await driver.BrowsingContext.GetTreeAsync(
new GetTreeCommandParameters());
foreach (BrowsingContextInfo context in tree.ContextTree)
{
if (context.UserContextId == userContextId)
{
await driver.BrowsingContext.CloseAsync(
new CloseCommandParameters(context.BrowsingContextId));
}
}
Locating Elements
The Browsing Context module provides element location functionality.
Locate by CSS Selector
LocateNodesCommandParameters parameters = new LocateNodesCommandParameters(
contextId,
new CssLocator("button.submit"));
LocateNodesCommandResult result = await driver.BrowsingContext.LocateNodesAsync(parameters);
foreach (NodeRemoteValue node in result.Nodes)
{
Console.WriteLine($"Found element: {node.SharedId}");
}
Locate by XPath
LocateNodesCommandParameters parameters = new LocateNodesCommandParameters(
contextId,
new XPathLocator("//button[@type='submit']"));
LocateNodesCommandResult result = await driver.BrowsingContext.LocateNodesAsync(parameters);
Locate with Maximum Results
LocateNodesCommandParameters parameters = new LocateNodesCommandParameters(
contextId,
new CssLocator("input"))
{
MaxNodeCount = 5 // Return at most 5 elements
};
LocateNodesCommandResult result = await driver.BrowsingContext.LocateNodesAsync(parameters);
Locate Within Element
LocateNodesCommandResult parentResult = await driver.BrowsingContext.LocateNodesAsync(
new LocateNodesCommandParameters(contextId, new CssLocator("#container")));
if (!parentResult.Nodes[0].TryAs(out NodeRemoteValue? parent))
{
return;
}
LocateNodesCommandParameters parameters = new LocateNodesCommandParameters(
contextId,
new CssLocator("button"))
{
};
parameters.StartNodes.Add(parent.ToSharedReference());
LocateNodesCommandResult result = await driver.BrowsingContext.LocateNodesAsync(parameters);
Setting Viewport
The Browsing Context module provides SetViewportAsync to control the viewport dimensions and device pixel ratio of a browsing context. This is useful for responsive layouts, mobile emulation, and consistent screenshot capture.
Set Viewport Size
SetViewportCommandParameters parameters = new SetViewportCommandParameters
{
BrowsingContextId = contextId,
Viewport = new Viewport
{
Width = 800,
Height = 600
},
DevicePixelRatio = 1.0
};
await driver.BrowsingContext.SetViewportAsync(parameters);
Reset Viewport to Default
To restore the viewport to its default dimensions, use SetViewportCommandParameters.ResetToDefaultViewport:
SetViewportCommandParameters parameters = new SetViewportCommandParameters
{
BrowsingContextId = contextId,
Viewport = SetViewportCommandParameters.ResetToDefaultViewport
};
await driver.BrowsingContext.SetViewportAsync(parameters);
Content Security Policy Bypass
Use SetBypassCSPAsync to enable or disable Content Security Policy (CSP) bypass for specific browsing contexts. This is useful when testing pages that enforce strict CSP rules or when loading resources that would otherwise be blocked.
Enable CSP Bypass
SetBypassCSPCommandParameters parameters = new SetBypassCSPCommandParameters
{
Contexts = { contextId },
Bypass = true
};
await driver.BrowsingContext.SetBypassCSPAsync(parameters);
Clear CSP Bypass Override
To restore default CSP behavior, use SetBypassCSPCommandParameters.ResetBypassCSP:
SetBypassCSPCommandParameters parameters = SetBypassCSPCommandParameters.ResetBypassCSP;
parameters.Contexts.Add(contextId);
await driver.BrowsingContext.SetBypassCSPAsync(parameters);
Capturing Screenshots
Screenshot of Entire Viewport
CaptureScreenshotCommandParameters parameters =
new CaptureScreenshotCommandParameters(contextId);
CaptureScreenshotCommandResult result =
await driver.BrowsingContext.CaptureScreenshotAsync(parameters);
// result.Data is base64-encoded PNG
byte[] imageBytes = Convert.FromBase64String(result.Data);
await File.WriteAllBytesAsync("screenshot.png", imageBytes);
Screenshot of Specific Element
// First locate the element
LocateNodesCommandResult locateResult = await driver.BrowsingContext.LocateNodesAsync(
new LocateNodesCommandParameters(contextId, new CssLocator("#chart")));
if (!locateResult.Nodes[0].TryAs(out NodeRemoteValue? element))
{
return;
}
// Capture element screenshot
CaptureScreenshotCommandParameters parameters =
new CaptureScreenshotCommandParameters(contextId)
{
Clip = new ElementClipRectangle(element.ToSharedReference())
};
CaptureScreenshotCommandResult result =
await driver.BrowsingContext.CaptureScreenshotAsync(parameters);
Clipped Screenshot
CaptureScreenshotCommandParameters parameters =
new CaptureScreenshotCommandParameters(contextId)
{
Clip = new BoxClipRectangle()
{
X = 100,
Y = 100,
Width = 800,
Height = 600
}
};
CaptureScreenshotCommandResult result =
await driver.BrowsingContext.CaptureScreenshotAsync(parameters);
Printing to PDF
PrintCommandParameters parameters = new PrintCommandParameters(contextId);
PrintCommandResult result = await driver.BrowsingContext.PrintAsync(parameters);
// result.Data is base64-encoded PDF
byte[] pdfBytes = Convert.FromBase64String(result.Data);
await File.WriteAllBytesAsync("page.pdf", pdfBytes);
PDF with Custom Settings
PrintCommandParameters parameters = new PrintCommandParameters(contextId)
{
Orientation = PrintOrientation.Landscape,
Scale = 0.8,
Background = true, // Print background colors/images
Page = new PrintPageParameters()
{
// Page size and margins are centimeters, not inches. These are US Letter.
Height = 27.94,
Width = 21.59,
},
Margins = new PrintMarginParameters()
{
Top = 1.27,
Bottom = 1.27,
Left = 1.27,
Right = 1.27,
},
};
PrintCommandResult result = await driver.BrowsingContext.PrintAsync(parameters);
Screencasting
StartScreencastAsync begins a screencast of a browsing context, and StopScreencastAsync ends it.
Pass a StartScreencastCommandParameters (configuring the target context, and optionally the
DestinationFolder the screencast file is saved to, the output MimeType, and Video/Audio track
settings) to start the capture. The result carries a
ScreencastId; stopping requires that ID, passed in the StopScreencastCommandParameters
constructor. Screencast output is written by the remote end for the duration of the capture.
Handling User Prompts
Accept Alert/Confirm
driver.BrowsingContext.OnUserPromptOpened.AddObserver((UserPromptOpenedEventArgs e) =>
{
Console.WriteLine($"Prompt: {e.Message}");
});
SubscribeCommandParameters subscribe =
new SubscribeCommandParameters(driver.BrowsingContext.OnUserPromptOpened.EventName);
await driver.Session.SubscribeAsync(subscribe);
// When prompt appears, handle it
HandleUserPromptCommandParameters handleParams =
new HandleUserPromptCommandParameters(contextId);
handleParams.Accept = true; // Click OK/Accept
await driver.BrowsingContext.HandleUserPromptAsync(handleParams);
Dismiss Prompt
HandleUserPromptCommandParameters parameters =
new HandleUserPromptCommandParameters(contextId);
parameters.Accept = false; // Click Cancel
await driver.BrowsingContext.HandleUserPromptAsync(parameters);
Enter Text in Prompt
// For prompt() dialogs that accept user input
HandleUserPromptCommandParameters parameters =
new HandleUserPromptCommandParameters(contextId);
parameters.Accept = true;
parameters.UserText = "My input text";
await driver.BrowsingContext.HandleUserPromptAsync(parameters);
Activation
Bring Tab to Foreground
ActivateCommandParameters parameters = new ActivateCommandParameters(contextId);
await driver.BrowsingContext.ActivateAsync(parameters);
Events
Navigation Events
The browsing context module raises seven navigation events, each carrying NavigationEventArgs:
OnNavigationStarted, OnNavigationCommitted, OnFragmentNavigated (a same-document navigation to a
URL fragment), OnDomContentLoaded, OnLoad, OnNavigationFailed, and OnNavigationAborted.
Three further events accompany a navigation but carry their own argument types: OnHistoryUpdated
(HistoryUpdatedEventArgs), OnDownloadWillBegin (DownloadWillBeginEventArgs) and OnDownloadEnd
(DownloadEndEventArgs). The sample below subscribes to those alongside the navigation events.
// Page load complete
driver.BrowsingContext.OnLoad.AddObserver((NavigationEventArgs e) =>
{
Console.WriteLine($"Page loaded: {e.Url}");
});
// DOM ready
driver.BrowsingContext.OnDomContentLoaded.AddObserver((NavigationEventArgs e) =>
{
Console.WriteLine($"DOM ready: {e.Url}");
});
// Navigation started
driver.BrowsingContext.OnNavigationStarted.AddObserver((NavigationEventArgs e) =>
{
Console.WriteLine($"Navigation started to: {e.Url}");
});
// Navigation failed
driver.BrowsingContext.OnNavigationFailed.AddObserver((NavigationEventArgs e) =>
{
Console.WriteLine($"Navigation failed: {e.Url}");
});
// Navigation committed to the session history
driver.BrowsingContext.OnNavigationCommitted.AddObserver((NavigationEventArgs e) =>
{
Console.WriteLine($"Navigation committed: {e.Url}");
});
// History entry updated via pushState/replaceState
driver.BrowsingContext.OnHistoryUpdated.AddObserver((HistoryUpdatedEventArgs e) =>
{
Console.WriteLine($"History updated: {e.Url}");
});
// Download about to begin
driver.BrowsingContext.OnDownloadWillBegin.AddObserver((DownloadWillBeginEventArgs e) =>
{
Console.WriteLine($"Download starting: {e.SuggestedFileName} from {e.Url}");
});
// Download completed or canceled; only a completed download has a file path
driver.BrowsingContext.OnDownloadEnd.AddObserver((DownloadEndEventArgs e) =>
{
Console.WriteLine($"Download ended with status: {e.Status}");
if (e.TryAs(out DownloadCompleteEventArgs? complete) && complete.FilePath != null)
{
Console.WriteLine($"Saved to: {complete.FilePath}");
}
});
Context Lifecycle Events
OnContextCreated carries ContextCreatedEventArgs and OnContextDestroyed carries
ContextDestroyedEventArgs. Both expose the same context properties as a BrowsingContextInfo in a
GetTreeAsync result (BrowsingContextId, Url, UserContextId, ClientWindowId, OriginalOpener,
Parent, and Children). ContextCreatedEventArgs adds HasPlannedNavigation,
which is true when the browser will navigate the new context right after the event is sent. In that
case, Url is usually the initial about:blank rather than the page the context will load.
// New tab/window/iframe created
driver.BrowsingContext.OnContextCreated.AddObserver((ContextCreatedEventArgs e) =>
{
Console.WriteLine($"Context created: {e.BrowsingContextId}");
Console.WriteLine($"URL: {e.Url}");
Console.WriteLine($"Original opener: {e.OriginalOpener ?? "user-initiated"}");
Console.WriteLine($"Navigation planned: {e.HasPlannedNavigation}");
});
// Tab/window closed
driver.BrowsingContext.OnContextDestroyed.AddObserver((ContextDestroyedEventArgs e) =>
{
Console.WriteLine($"Context destroyed: {e.BrowsingContextId}");
});
User Prompt Events
// Alert/confirm/prompt opened
driver.BrowsingContext.OnUserPromptOpened.AddObserver((UserPromptOpenedEventArgs e) =>
{
Console.WriteLine($"Prompt type: {e.PromptType}");
Console.WriteLine($"Message: {e.Message}");
});
// Prompt closed
driver.BrowsingContext.OnUserPromptClosed.AddObserver((UserPromptClosedEventArgs e) =>
{
Console.WriteLine($"Prompt closed with accept={e.IsAccepted}");
if (e.UserText != null)
{
Console.WriteLine($"User entered: {e.UserText}");
}
});
Download Events
OnDownloadWillBegin fires when the browser is about to begin a file download. The event args
(DownloadWillBeginEventArgs) carry the download ID (DownloadId), the suggested file name
(SuggestedFileName), the originating URL (Url), and the browsing context ID
(BrowsingContextId).
OnDownloadEnd fires when the download finishes. The event args (DownloadEndEventArgs) carry
the same DownloadId and Url, along with Status (DownloadEndStatus.Complete or
DownloadEndStatus.Canceled). DownloadEndEventArgs is abstract, and the status decides its type. A
completed download arrives as DownloadCompleteEventArgs, whose FilePath is the path of the
downloaded file, or null when the remote end cannot supply one. A canceled download arrives as
DownloadCanceledEventArgs, which has no file path. To reach FilePath, call
TryAs<DownloadCompleteEventArgs>(), or As<DownloadCompleteEventArgs>() when the download is known to
have completed; As<T>() throws a WebDriverBiDiException when the event args are the other type.
driver.BrowsingContext.OnDownloadWillBegin.AddObserver((DownloadWillBeginEventArgs e) =>
{
Console.WriteLine($"Download starting: {e.SuggestedFileName}");
Console.WriteLine($" Context: {e.BrowsingContextId}");
Console.WriteLine($" URL: {e.Url}");
Console.WriteLine($" Download: {e.DownloadId}");
});
driver.BrowsingContext.OnDownloadEnd.AddObserver((DownloadEndEventArgs e) =>
{
Console.WriteLine($"Download {e.DownloadId} ended: {e.Status}");
if (e.TryAs(out DownloadCompleteEventArgs? complete) && complete.FilePath != null)
{
Console.WriteLine($" Saved to: {complete.FilePath}");
}
});
Note: Both events must be subscribed to via
Session.SubscribeAsyncbefore they are delivered. Use"browsingContext.downloadWillBegin"and"browsingContext.downloadEnd"as the event names.
Common Patterns
Wait for Page Load Pattern
SubscribeCommandParameters subscribe =
new SubscribeCommandParameters(driver.BrowsingContext.OnLoad.EventName);
await driver.Session.SubscribeAsync(subscribe);
EventObserver<NavigationEventArgs> observer =
driver.BrowsingContext.OnLoad.AddObserver((e) => { });
observer.StartCapturingTasks();
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, url));
Task[] tasks = await observer.WaitForCapturedTasksAsync(1, TimeSpan.FromSeconds(30));
bool loaded = tasks.Length == 1;
observer.StopCapturingTasks();
if (!loaded)
{
Console.WriteLine("Page load timeout!");
}
Multi-Tab Pattern
// Open multiple tabs
List<string> contextIds = new List<string>();
for (int i = 0; i < 3; i++)
{
CreateCommandResult result = await driver.BrowsingContext.CreateAsync(
new CreateCommandParameters(CreateType.Tab));
contextIds.Add(result.BrowsingContextId);
}
// Navigate each tab
foreach (string contextId in contextIds)
{
await driver.BrowsingContext.NavigateAsync(
new NavigateCommandParameters(contextId, $"https://example.com/page{contextIds.IndexOf(contextId)}"));
}
// Close all tabs
foreach (string contextId in contextIds)
{
await driver.BrowsingContext.CloseAsync(
new CloseCommandParameters(contextId));
}
Best Practices
- Always wait for readiness: Use
ReadinessState.Completefor reliable automation - Handle prompts: Set up observers for user prompts before triggering actions that may create them
- Clean up contexts: Close tabs when done to free resources
- Use appropriate locators: CSS selectors are generally faster than XPath
- Cache context IDs: Store context IDs rather than repeatedly calling GetTree
Error Handling
Commands in this module throw WebDriverBiDiCommandException when the browser returns a protocol error response (for example, when a browsing context ID is invalid or a navigation target cannot be reached), and WebDriverBiDiTimeoutException when a command exceeds its timeout. See the Error Handling guide for full details on exception types, TransportErrorBehavior options, and recommended catch patterns.
Next Steps
- Script Module: Execute JavaScript in browsing contexts
- Input Module: Simulate user interactions
- Network Module: Monitor navigation traffic
- Examples: See complete examples
API Reference
See the API documentation for complete details on all classes and methods.