Skip to content

Releases: hardkoded/puppeteer-sharp

v24.40.0

20 Mar 17:39
916e6b6

Choose a tag to compare

What's Changed

New Contributors

Full Changelog: v24.39.1...v24.40.0

v24.39.1

18 Mar 15:41
bab0eb0

Choose a tag to compare

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

10 Mar 18:37
284c33e

Choose a tag to compare

What's Changed

  • Bump Firefox nightly to 150.0a1 by @kblok in #3376
  • Roll to Chrome 146.0.7680.66 (upstream PR #14752) by @kblok in #3375
  • Expose Page.HasDevToolsAsync (upstream PR #14758) by @kblok in #3377
  • Bump version to 24.39.0 by @kblok in #3378

Full Changelog: v24.38.8...v24.39.0

v24.38.8

09 Mar 12:51
4b8d021

Choose a tag to compare

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 child

Locator.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 == true

BrowserContext.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); // false

Keyboard-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 IsolateSandboxedIframes trial 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.getProperties for improved performance (#3227)
  • Fix: frameElement() should return handles in the main world (#3233)
  • Fix: WaitForSelector should work for pseudo classes (#3228)
  • Fix: Support out-of-process iframes in exposeFunction (#3235)
  • Fix: Correct content-length header for res...
Read more

v21.1.1

19 Feb 12:23
82386c6

Choose a tag to compare

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

Full Changelog: v21.1.0...v21.1.1

v21.1.0

18 Feb 02:51
0158f7d

Choose a tag to compare

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

Full Changelog: v21.0.1...v21.1.0

v21.0.1

12 Feb 15:08
b94dc7a

Choose a tag to compare

What's Changed

  • Use stable WebDriverBiDi-Relaxed 0.0.41 by @kblok in #3125

Full Changelog: v21.0.0...v21.0.1

v21.0.0

11 Feb 21:32
ef35a3a

Choose a tag to compare

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

31 Jan 21:18
8799a9e

Choose a tag to compare

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

09 Dec 18:47
c23456f

Choose a tag to compare

What's Changed

New Contributors

Full Changelog: 20.2.4...v20.2.5