Table of Contents

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);

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 load
  • ReadinessState.Interactive: Wait for DOM ready
  • ReadinessState.Complete: Wait for full page load (including images, CSS)

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

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.SubscribeAsync before 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

  1. Always wait for readiness: Use ReadinessState.Complete for reliable automation
  2. Handle prompts: Set up observers for user prompts before triggering actions that may create them
  3. Clean up contexts: Close tabs when done to free resources
  4. Use appropriate locators: CSS selectors are generally faster than XPath
  5. 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

API Reference

See the API documentation for complete details on all classes and methods.