puppeteer-sharp is a free, open source data extraction & web scraping project written in C# and released under MIT. It has 3,919 GitHub stars, 482 forks and 11 open issues, and was last pushed 8 hours ago. On this registry it ranks #34 of 45 tracked projects in Data Extraction & Web Scraping, with 5 head-to-head comparisons available.

What is puppeteer-sharp?

Puppeteer Sharp is an MIT-licensed .NET port of the official Node.js Puppeteer API, giving C# developers headless Chrome automation for screenshots, PDF generation, content extraction, and end-to-end testing without leaving the .NET toolchain.

What it is

Puppeteer Sharp is a C# library that reimplements the official Node.js Puppeteer API on top of .NET. It ships through NuGet in three packages: PuppeteerSharp for full cross-browser automation, PuppeteerSharp.Cdp for Chrome-only AOT applications where binary size matters, and PuppeteerSharp.AspNetFramework as the companion library for ASP.NET Classic. The library comes in two flavours — a NetStandard 2.0 build targeting .NET Framework 4.6.1 and .NET Core 2.0 or greater, and a .NET 8 build. Source lives at hardkoded/puppeteer-sharp under the MIT licence, with documentation and API reference hosted at puppeteersharp.com.

The problem it solves is toolchain fragmentation. Browser automation in the Node.js world is dominated by Puppeteer, but a C# team that needs to drive Chrome or Chromium — for screenshots, PDF rendering, crawling, or browser tests — would otherwise have to maintain a separate Node.js process, a second runtime, and a second set of deployment dependencies alongside its .NET application. Puppeteer Sharp replaces that parallel Node.js stack: the same API shape (LaunchAsync, NewPageAsync, GoToAsync, ScreenshotAsync, PdfAsync) is available directly inside a .NET process, so automation code lives in the same solution, uses the same build pipeline, and deploys with the same artifacts as the rest of the application.

Key capabilities

  • Cross-browser automation through the PuppeteerSharp package; Chrome-only deployments use PuppeteerSharp.Cdp when AOT compilation and small binary size matter.
  • Screenshot generation with ScreenshotAsync, including a configurable viewport via SetViewportAsync with ViewPortOptions Width and Height.
  • PDF rendering with PdfAsync, where waiting on EvaluateExpressionHandleAsync("document.fonts.ready") prevents fonts loaded from a CDN from rendering as missing text.
  • Browser management through BrowserFetcher and DownloadAsync, which fetch the browser binary that Puppeteer.LaunchAsync then launches with LaunchOptions such as Headless = true.
  • HTML injection and extraction with SetContentAsync and GetContentAsync, useful for rendering generated markup or pulling back page state.
  • Firefox testing via WebDriver BiDi, added in the PuppeteerSharp 21 release line.
  • AOT compilation support, added in the PuppeteerSharp 19 release line.

Who uses it and how

  • C# teams running e2e and browser test suites, keeping test code in the same .NET projects and CI pipeline as the application under test.
  • Crawling and scraping workloads, where GoToAsync plus GetContentAsync or in-page evaluation drives extraction pipelines.
  • Reporting and document services that render HTML to PDF or capture screenshots server-side, including the font-readiness wait that HTML-to-PDF rendering requires.
  • ASP.NET Classic applications, which use the PuppeteerSharp.AspNetFramework companion package to run the library in that hosting model.
  • Linux deployments, which need an X-server present even for headless runs; the upstream Puppeteer troubleshooting guide is the reference for Chrome-on-Linux issues.

Getting started

Install the PuppeteerSharp package from NuGet, then call BrowserFetcher.DownloadAsync() to fetch the browser and Puppeteer.LaunchAsync with LaunchOptions to start it. API documentation and working snippets for screenshots, PDFs, and HTML injection are published at puppeteersharp.com, with questions handled on Stack Overflow and the #puppeteer-sharp Slack channel.

How it compares

The reference implementation for this API is the official Node.js Puppeteer, and Puppeteer Sharp tracks it deliberately as a port rather than an independent design; existing Puppeteer knowledge transfers, and release notes are framed around the upstream API. Among the tools named in the project's facts, it therefore occupies the .NET side of the same automation model rather than competing with it, which is why the maintainers point users at the Node.js repository for browser troubleshooting.

When to use it — and when not to

A self-hoster must operate the browser binary that BrowserFetcher downloads, keep it versioned in CI, and provide an X-server on Linux hosts, so the runtime footprint is larger than a pure library dependency. Teams that want a managed browser service, avoid .NET, or only need static HTML parsing should not pick it. The README is largely usage snippets and links rather than a full install and quickstart guide, so expect to lean on the API documentation and community channels for setup details.

project readme (upstream, from github) — read inline

Puppeteer Sharp

NuGet Build status Demo build status Backers

Puppeteer Sharp is a .NET port of the official Node.JS Puppeteer API.

Recent news

Test the latest Firefox versions using WebDriver BiDi! Check the PuppeteerSharp 21 release notes.

PuppeteerSharp now supports AOT compilation! Check the PuppeteerSharp 19 release notes!.

Useful links

Published Packages

Package Description
PuppeteerSharp Our full cross-browser automation tool
PuppeteerSharp.Cdp Ideal for Chrome-only AOT apps where binary size matters
PuppeteerSharp.AspNetFramework The companion library you need to run PuppeteerSharp in ASP.NET Classic

Prerequisites

  • Puppeteer-Sharp comes in two flavors: a NetStandard 2.0 library for .NET Framework 4.6.1 and .NET Core 2.0 or greater and a .NET 8 version.
  • If you have issues running Chrome on Linux, the Puppeteer repo has a great troubleshooting guide.
  • X-server is required on Linux.

How to Contribute and Provide Feedback

Some of the best ways to contribute are to try things out file bugs and fix issues.

If you have an issue or a question:

Contributing Guide

See this document for information on how to contribute.

Usage

Take screenshots

var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(
    new LaunchOptions { Headless = true });
await using var page = await browser.NewPageAsync();
await page.GoToAsync("http://www.google.com");
await page.ScreenshotAsync(outputFile);

snippet source | anchor

You can also change the view port before generating the screenshot

await Page.SetViewportAsync(new ViewPortOptions
{
    Width = 500,
    Height = 500
});

snippet source | anchor

Generate PDF files

var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true });
await using var page = await browser.NewPageAsync();
await page.GoToAsync("http://www.google.com"); // In case of fonts being loaded from a CDN, use WaitUntilNavigation.Networkidle0 as a second param.
await page.EvaluateExpressionHandleAsync("document.fonts.ready"); // Wait for fonts to be loaded. Omitting this might result in no text rendered in pdf.
await page.PdfAsync(outputFile);

snippet source | anchor

Inject HTML

await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<div>My Receipt</div>");
var result = await page.GetContentAsync();

snippet source | anchor

Evaluate Javascript

await using var page = await browser.NewPageAsync();
var seven = await page.EvaluateExpressionAsync<int>("4 + 3");
var someObject = await page.EvaluateFunctionAsync<JsonElement>("(value) => ({a: value})", 5);
Console.WriteLine(someObject.GetProperty("a").GetString());

snippet source | anchor

Wait For Selector

using (var page = await browser.NewPageAsync())
{
    await page.GoToAsync("http://www.spapage.com");
    await page.WaitForSelectorAsync("div.main-content")
    await page.PdfAsync(outputFile));
}

Wait For Function

using (var page = await browser.NewPageAsync())
{
    await page.GoToAsync("http://www.spapage.com");
    var watchDog = page.WaitForFunctionAsync("()=> window.innerWidth < 100");
    await page.SetViewportAsync(new ViewPortOptions { Width = 50, Height = 50 });
    await watchDog;
}

Connect to a remote browser

var options = new ConnectOptions()
{
    BrowserWSEndpoint = $"wss://www.externalbrowser.io?token={apikey}"
};

var url = "https://www.google.com/";

using (var browser = await PuppeteerSharp.Puppeteer.ConnectAsync(options))
{
    using (var page = await browser.NewPageAsync())
    {
        await page.GoToAsync(url);
        await page.PdfAsync("wot.pdf");
    }
}

Sponsors

PuppeteerSharp is sponsored by IronPDF, a commercial C# .NET PDF library and HTML-to-PDF alternative with Chrome rendering, PDF editing, digital signatures, encryption, enterprise licensing, and 24/7 engineering support.

IronPDF logo.

A massive thanks to JetBrains for a community Resharper and Rider license to use on this project.

JetBrains logo.

And a huge thanks to everyone who sponsors this project through Github sponsors:

Frequently asked questions

Is puppeteer-sharp free to use?

puppeteer-sharp is open source under the MIT licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does puppeteer-sharp do?

Headless Chrome .NET API

What is puppeteer-sharp written in?

puppeteer-sharp is primarily written in C#. Its source is publicly available at https://github.com/hardkoded/puppeteer-sharp, and it has 3,919 GitHub stars.