Releases: hardkoded/puppeteer-sharp
v24.40.0
What's Changed
- Improve memory usage by @albyrock87 in #3393
- feat: support PUPPETEER_DANGEROUS_NO_SANDBOX environment variable by @kblok in #3395
- Roll Chrome to 146.0.7680.153 by @kblok in #3394
- Bump version to 24.40.0 by @kblok in #3396
New Contributors
- @albyrock87 made their first contribution in #3393
Full Changelog: v24.39.1...v24.40.0
v24.39.1
What's New
- Add includeAll parameter to PagesAsync by @kblok in #3380
- Add ElementHandle.AsLocator() (upstream alignment) by @kblok in #3383
- Add SetUserAgentAsync options overload with platform support by @kblok in #3382
- Add cookie shortcuts to IBrowser by @kblok in #3379
- Add Locator.FilterHandle() and MapHandle() by @kblok in #3381
- Enable Chrome BiDi protocol support via BiDi-over-CDP bridge by @kblok in #3385
- Bump Chrome to 146.0.7680.76 by @kblok in #3386
- Add pipe transport support for Chrome/Chromium by @kblok in #3384
What's Changed
- Add missing JsonSerializable attribute for RequestWillBeSentExtraInfoResponse by @kblok in #3388
- Fix #3389: CDP client closing when browser console logs DOM element by @kblok in #3390
- Use AnonymousPipeServerStream for pipe transport, enabling Windows support by @kblok in #3392
- chore: clean up TestExpectations.upstream.json by @kblok in #3391
Full Changelog: v24.39.0...v24.39.1
v24.39.0
v24.38.8
PuppeteerSharp v24.38.0
New Features
Browser updates
- Roll to Chrome 146.0.7680.31 (#3368)
P-Selector Support
Full support for Puppeteer pseudo-class selectors (::-p-text, ::-p-aria, deep combinators >>> and >>>>).
// Text selector
var element = await page.QuerySelectorAsync("button::-p-text(Submit)");
// ARIA selector
var element = await page.QuerySelectorAsync("div::-p-aria(Dialog)");
// Deep shadow DOM combinators
var elements = await page.QuerySelectorAllAsync("div >>> span"); // deep descendant
var element = await page.QuerySelectorAsync("div >>>> span"); // direct shadow childLocator.Race
Race multiple locators and use whichever matches first.
await Locator.Race(
page.Locator("#login-button"),
page.Locator("#signup-button")
).ClickAsync();Locator.Filter
Filter matched elements with a JavaScript predicate.
await page.Locator("button")
.Filter("(element) => element.getAttribute('data-active') === 'true'")
.ClickAsync();Locator.Map
Transform locator values before consuming them.
var text = await page.Locator("h1")
.Map("(element) => element.textContent")
.WaitAsync<string>();Locator.WaitHandleAsync
Wait for a locator to resolve and get an IJSHandle back.
var handle = await page.Locator("div#content").WaitHandleAsync();Locator.WaitAsync
Wait for a locator to resolve, optionally extracting a typed value.
// Wait for element to exist
await page.Locator("div.loaded").WaitAsync();
// Wait and extract a typed value
var count = await page.Locator("#counter")
.Map("(el) => parseInt(el.textContent)")
.WaitAsync<int>();Function Locators
Create locators from arbitrary JavaScript functions.
var result = await page.LocatorFunction(@"() => {
return document.querySelector('.dynamic-content')?.textContent;
}").WaitAsync<string>();Locator Support for Frames
Locators now work on IFrame in addition to IPage.
var frame = page.Frames.First(f => f.Name == "my-iframe");
await frame.Locator("button.submit").ClickAsync();Autofill Support
Autofill credit card forms via ElementHandle.AutofillAsync.
var input = await page.WaitForSelectorAsync("#card-number");
await input.AutofillAsync(new AutofillData
{
CreditCard = new CreditCardData
{
Number = "4444444444444444",
Name = "John Smith",
ExpiryMonth = "01",
ExpiryYear = "2030",
Cvc = "123",
},
});Bluetooth Emulation
Emulate Bluetooth adapter state and simulate preconnected peripherals.
await page.Bluetooth.EmulateAdapterAsync(AdapterState.PoweredOn);
await page.Bluetooth.SimulatePreconnectedPeripheralAsync(new PreconnectedPeripheral
{
Address = "09:09:09:09:09:09",
Name = "MY_DEVICE",
ManufacturerData = [new BluetoothManufacturerData { Key = 17, Data = "AP8BAX8=" }],
KnownServiceUuids = ["12345678-1234-5678-9abc-def123456789"],
});Browser Extension Management
Install and uninstall Chrome extensions at runtime.
var extensionId = await browser.InstallExtensionAsync("/path/to/extension");
// ... use the extension ...
await browser.UninstallExtensionAsync(extensionId);EnableExtensions Launch Option
Launch the browser with extension support enabled.
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
EnableExtensions = true,
});Page.OpenDevToolsAsync
Programmatically open DevTools for a page, returns the DevTools page.
var devtoolsPage = await page.OpenDevToolsAsync();Page.EmulateFocusedPageAsync
Emulate the page being focused (even when running headless).
await page.EmulateFocusedPageAsync(true);
var hasFocus = await page.EvaluateFunctionAsync<bool>("() => document.hasFocus()");
// hasFocus == trueBrowserContext.SetPermissionAsync
Set permissions with fine-grained control using PermissionEntry.
await context.SetPermissionAsync(TestConstants.EmptyPage, new PermissionEntry
{
Permission = new PermissionDescriptor { Name = "geolocation" },
State = PermissionState.Granted,
});Browser.DeleteMatchingCookiesAsync
Delete cookies matching specific filters.
await context.DeleteMatchingCookiesAsync(new DeleteCookiesRequest
{
Name = "session",
Domain = ".example.com",
});Browser-Level Cookie API
GetCookiesAsync, SetCookieAsync, and DeleteCookieAsync now available on IBrowserContext directly.
var cookies = await context.GetCookiesAsync();
await context.SetCookieAsync(new CookieParam { Name = "foo", Value = "bar", Url = "https://example.com" });ResourceTiming & Request.Initiator
Access detailed timing information and request initiator stack traces.
Page.Request += (_, e) =>
{
var initiator = e.Request.Initiator;
Console.WriteLine($"Type: {initiator.Type}, URL: {initiator.Url}");
};
Page.Response += (_, e) =>
{
var timing = e.Response.Timing;
Console.WriteLine($"DNS: {timing.DnsEnd - timing.DnsStart}ms");
};InterceptResolutionState on IRequest
Check the current interception resolution state and whether it's been handled.
Page.Request += async (_, e) =>
{
var state = e.Request.InterceptResolutionState;
if (!e.Request.IsInterceptResolutionHandled)
{
await e.Request.ContinueAsync();
}
};CancellationToken in WaitForSelectorAsync
Pass a CancellationToken to cancel long-running selector waits.
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var element = await page.WaitForSelectorAsync(".dynamic", new WaitForSelectorOptions
{
CancellationToken = cts.Token,
});QueryOptions for QuerySelectorAllAsync
Opt out of sandbox isolation for better performance when querying many elements.
var elements = await page.QuerySelectorAllAsync("div.item", new QueryOptions { Isolate = false });PdfOptions.Timeout
Set a timeout for PDF generation.
var pdf = await page.PdfDataAsync(new PdfOptions { Timeout = 30_000 });PdfOptions.WaitForFonts
Control whether to wait for document.fonts.ready before generating PDFs (defaults to true).
var pdf = await page.PdfDataAsync(new PdfOptions { WaitForFonts = false });ElementHandle.BackendNodeIdAsync
Get the CDP backend node ID for an element.
var handle = await page.QuerySelectorAsync("#my-element");
var backendNodeId = await handle.BackendNodeIdAsync();CDPSession.Detached Property
Check if a CDP session has been detached.
var client = await page.CreateCDPSessionAsync();
Console.WriteLine(client.Detached); // falseKeyboard-Lock and Pointer-Lock Permissions
New permission types for OverridePermissionsAsync.
await context.OverridePermissionsAsync(url, new[]
{
OverridePermission.KeyboardLock,
OverridePermission.PointerLock,
});Offline Support in EmulateNetworkConditionsAsync
Set the Offline parameter directly in network conditions.
await page.EmulateNetworkConditionsAsync(new NetworkConditions
{
Offline = true,
});IgnoreCache in Page.ReloadAsync
Force-reload ignoring the browser cache.
await page.ReloadAsync(new ReloadOptions { IgnoreCache = true });ReducedContrast Vision Deficiency
New VisionDeficiency.ReducedContrast option.
await page.EmulateVisionDeficiencyAsync(VisionDeficiency.ReducedContrast);HandleDevToolsAsPage Option
Treat DevTools windows as regular pages when connecting.
var browser = await Puppeteer.ConnectAsync(new ConnectOptions
{
BrowserWSEndpoint = endpoint,
HandleDevToolsAsPage = true,
});Disable Network Events
Disable network event tracking for improved performance.
await page.SetNetworkEventsEnabledAsync(false);ElementHandle Touch API & JSHandle.Move
Touch actions on elements and Move() to prevent handle auto-disposal.
// Touch an element
await elementHandle.TouchStartAsync();
await elementHandle.TouchMoveAsync();
await elementHandle.TouchEndAsync();
// Prevent a handle from being disposed
IJSHandle handle;
await using (var temp = await page.EvaluateExpressionHandleAsync("document"))
{
handle = temp.Move(); // handle survives the using block
}Configurable EvaluationScriptUrl (Stealth Mode)
Customize the internal evaluation script URL to avoid bot detection.
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
EvaluationScriptUrl = "__custom_eval__",
});Bug Fixes
- Fix: Support clip in
ElementHandle.ScreenshotAsync(#3271) - Fix: Increase frame tree sync timeout to prevent premature connection close (#3276)
- Fix: Turn on PdfOopif for PDF viewer (#3273)
- Fix: Disable
IsolateSandboxedIframestrial to prevent flakiness (#3272) - Fix: Apply timeout to waiting for navigation response (#3268)
- Fix: Implement fallback to Chrome for Testing dashboard download URLs (#3267)
- Fix: Exposed functions should only be called once (#3225)
- Fix: Use
Runtime.getPropertiesfor improved performance (#3227) - Fix:
frameElement()should return handles in the main world (#3233) - Fix:
WaitForSelectorshould work for pseudo classes (#3228) - Fix: Support out-of-process iframes in
exposeFunction(#3235) - Fix: Correct content-length header for res...
v21.1.1
What's New
- Add support for 'Default' SameSite cookie property (#14637) by @kblok in #3151
- Implement page.CaptureHeapSnapshotAsync() (#3114) by @kblok in #3154
- Handle shadow DOM in Frame.FrameElementAsync (#13156) by @kblok in #3155
- Add local fonts to OverridePermissions enum by @ciaranodonnell in #3157
What's Changed
- Suppress xkbcomp warnings from Xvfb in CI by @kblok in #3148
- Remove other nupkg packages when building PuppeteerSharp.Cdp by @steveberdy in #3149
- feat(bidi): Improve window management error handling by @kblok in #3150
- Add Claude Code skills and settings by @kblok in #3156
- Implement frame.frameElement() for WebDriver BiDi by @kblok in #3152
New Contributors
- @ciaranodonnell made their first contribution in #3157
Full Changelog: v21.1.0...v21.1.1
v21.1.0
What's New
- New PuppeteerSharp.Cdp package with no WebDriverBidi dependency. Ideal for Chrome-only AOT projects by @steveberdy in #3135
- Migrate from .NET 8 to .NET 10 by @kblok in #3129
- Implement Page.ResizeAsync by @kblok in #3130
- Add Browser.ScreensAsync, AddScreenAsync, and RemoveScreenAsync methods (#14445) by @kblok in #3132
- Add support for background page creation (#14547) by @kblok in #3136
- Publish Browser.Get|SetWindowBounds and Page.WindowId (#14494) by @kblok in #3131
What's Changed
- Disable ReadAnythingOmniboxChip by default by @kblok in #3127
- Migrate from postData to postDataEntries in CdpHttpRequest by @kblok in #3126
- Enhance accessibility tree snapshot with more properties (#14643) by @kblok in #3128
- Fix flaky PageGoBackTests.ShouldWork by awaiting navigation response by @kblok in #3133
- Sync tracing tests with upstream Puppeteer by @kblok in #3137
- Use dynamic ports for test servers by @kblok in #3138
- Replace WebDriverBiDi-Relaxed with WebDriverBiDi 0.0.43 by @kblok in #3139
- Add Browser.CreateCDPSessionAsync() for browser-level CDP commands by @kblok in #3140
- Check executable path exists before skipping download by @andrewgee in #2905
- Deprecate Cookie attribute SameParty (#14550) by @kblok in #3142
- Fix ChromeHeadlessShell launch crash with Invalid browser error by @kblok in #3141
- Fix flaky ShouldProvideAccessToElements OOPIF test by @kblok in #3143
- Fix ChromeHeadlessShell launch crash by @kblok in #3146
- Update README with v21 news, packages, and JetBrains logo by @kblok in #3147
- Fix CookiePartitionKey serialization and add partition key test by @kblok in #3144
New Contributors
- @andrewgee made their first contribution in #2905
- @steveberdy made their first contribution in #3135
Full Changelog: v21.0.1...v21.1.0
v21.0.1
v21.0.0
New Features
- WebDriver BiDi protocol support for Firefox!!!!! PuppeteerSharp now supports the WebDriver BiDi protocol, enabling Firefox automation alongside existing Chrome/Chromium CDP support. Select the protocol via
LaunchOptions.Protocol. - New ProtocolType enum: ProtocolType.Cdp (default) and ProtocolType.WebdriverBiDi.
Breaking Changes
- AcceptInsecureCerts removed from IBrowser: This property was removed from the public interface. Insecure certs are now handled internally via the Security.setIgnoreCertificateErrors CDP command during browser creation.
- Non-generic EvaluateExpressionAsync() and EvaluateFunctionAsync() return type changed: Changed from Task<JsonElement?> to Task (void). If you need a return value, use the generic overloads EvaluateExpressionAsync() /
EvaluateFunctionAsync(). - IBrowserContext now extends IDisposable and IAsyncDisposable: Browser contexts should now be properly disposed.
- Several protected methods on Page changed to internal: OnFrameAttached, OnFrameDetached, OnFrameNavigated, OnRequestFailed, OnRequestFinished, OnRequestServedFromCache, OnResponse, OnDOMContentLoaded, OnLoad. These were
internal event-raising methods that should never have been protected. - CDPSession.Close() signature changed: From internal abstract void Close() to public abstract void Close(string closeReason).
Minor Changes
- Dependency updates: System.Text.Json upgraded to 10.0.0, Microsoft.Bcl.AsyncInterfaces upgraded to 10.0.0.
- New dependency: WebDriverBiDi-Relaxed 0.0.40-beta.1 added for BiDi protocol support.
- Custom query handlers are now global: CustomQuerySelectorRegistry changed from connection-scoped to a global singleton.
- Frame.AddScriptTagAsync() is now a concrete implementation on the base Frame class instead of abstract.
- Package now includes README.md in the NuGet package.
- Fix flaky ShouldReportScriptsAcrossNavigationsWhenDisabled test: Added WaitForNetworkIdleAsync() between navigations to prevent coverage data loss.
v20.2.6
What's Changed
- Mark LogProcess property as obsolete by @Copilot in #3072
- Fix ProxyServer default to allow browser context proxy inheritance by @Copilot in #3073
- Add bitness and wow64 properties to UserAgentMetadata by @Copilot in #3074
- Fix CookiePartitionKeyConverter to support string deserialization by @Copilot in #3075
- refactor: align ChromeTargetManager with Puppeteer PR #14602 by @Copilot in #3107
- Make sure we run Page.enable before Page.getFrameTree by @kblok in #3101
Full Changelog: v20.2.5...v20.2.6
v20.2.5
What's Changed
- Don't assume Params type by @bgrainger in #3028
New Contributors
- @bgrainger made their first contribution in #3028
Full Changelog: 20.2.4...v20.2.5