Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Playwright for .NET. Install the Microsoft.Playwright NuGet package, build the project, install Playwright’s browser binaries, navigate to the page, and call Page.ScreenshotAsync with a .png path. Set FullPage = true for the complete scrollable document, use a locator for one element, or omit the path to receive PNG bytes in memory.

What you need before writing code

  • .NET SDK and a C# console project.
  • The Microsoft.Playwright NuGet package.
  • A Playwright-managed browser binary (Chromium in the examples).
  • Network access to the target webpage, unless you are capturing local content.

The NuGet package is only the .NET API. Browser binaries are installed separately for the project output, so a package-only installation is incomplete.

Set up Playwright in a C# console app

  1. Create or open the project

    dotnet new console -n WebPngCapture
    cd WebPngCapture
  2. Add the Playwright package

    dotnet add package Microsoft.Playwright
  3. Build once

    dotnet build
  4. Install the browser binaries

    Run the generated Playwright installation script from the build output. Replace netX with the target framework directory shown under bin/Debug (for example, net8.0):

    pwsh bin/Debug/netX/playwright.ps1 install

    On a machine without PowerShell, use the equivalent script invocation supported by your environment. Run this installation again when your deployment image or Playwright version changes.

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Take a basic webpage screenshot

Replace Program.cs with this asynchronous console program:

using Microsoft.Playwright;

using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync();
var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com");
await page.ScreenshotAsync(new() { Path = "screenshot.png" });

Run it with dotnet run. The headless Chromium process navigates to the URL and writes screenshot.png in the application’s working directory. PNG is the default screenshot type, and Playwright can also infer the output type from a path extension.

Choose a viewport explicitly

Viewport dimensions affect responsive layouts. Set them before navigation so the page renders at a known CSS-pixel size:

var page = await browser.NewPageAsync(new() {
    ViewportSize = new() { Width = 1440, Height = 900 }
});
await page.GotoAsync("https://example.com");
await page.ScreenshotAsync(new() { Path = "desktop.png" });

For a mobile layout, choose a narrower viewport. If you need device-pixel output for a high-DPI style capture, configure the browser context’s device scale factor and keep that setting consistent between runs.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Capture a full-page PNG

A normal screenshot captures the current viewport. FullPage = true expands the capture to the page’s full scrollable height:

await page.GotoAsync("https://example.com");
await page.ScreenshotAsync(new() {
    Path = "full-page.png",
    FullPage = true
});

This produces one potentially very tall image. Long pages can consume substantial memory and may be inconvenient for downstream systems; use viewport shots or section captures when a fixed image size is required.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

Capture one element instead of the whole page

Use a locator when you need a component such as a header, chart, invoice, or article card:

await page.GotoAsync("https://example.com");
await page.Locator(".header").ScreenshotAsync(new() {
    Path = "header.png"
});

The locator must resolve to a visible element. Prefer stable attributes such as data-testid over presentation-only class names when you control the page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep the PNG in memory

Omit Path to receive the encoded image as a byte array. This is useful when an API, object store, message queue, or image processor consumes the result directly:

var bytes = await page.ScreenshotAsync();
await File.WriteAllBytesAsync("in-memory-copy.png", bytes);

The returned bytes are PNG data by default. You can pass them to another component without creating an intermediate file.

Screenshot options that matter

Output type and quality

PNG is lossless and is the default. Playwright also supports other image formats through its screenshot options, and a filename extension can select the format. The Quality setting applies to lossy formats, not PNG; changing it will not reduce a PNG’s size.

Headless versus headed mode

Playwright launches headless by default, which is appropriate for servers and CI. To watch the browser while diagnosing a page, launch with Headless = false:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await using var browser = await playwright.Chromium.LaunchAsync(new() {
    Headless = false
});

Headed operation requires a graphical environment and is usually unsuitable for a minimal Linux container unless a display server is configured.

Waiting for usable content

Navigation completion does not guarantee that images, fonts, or client-rendered data have settled. Wait for a meaningful selector before capturing:

await page.GotoAsync("https://example.com");
await page.Locator("main").WaitForAsync();
await page.ScreenshotAsync(new() { Path = "ready.png" });

For applications that continue loading data after the main element appears, wait for a page-specific state or a short, justified delay. Avoid arbitrary long sleeps when a deterministic selector or application signal is available.

Authentication and request context

If the page requires authentication, create a browser context with the required cookies, headers, or storage state before opening the page. Keep credentials out of source control and do not embed access tokens in URLs or screenshots.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make captures repeatable

Pixel comparisons are sensitive to the operating system, browser version, fonts, hardware, power mode, viewport, device scale factor, and headed versus headless mode. Use the same environment for the baseline and every comparison; separate baselines may be necessary for different browsers or platforms.

Control page state

  • Wait for the same application-ready selector on every run.
  • Disable or hide animations and blinking carets with page-specific CSS when testing visual output.
  • Move the pointer away from hover-sensitive controls.
  • Use fixed test data and stable fonts where possible.
  • Handle cookie notices, newsletter dialogs, chat widgets, and rotating content before capture.

These controls improve determinism, but they should reflect the state you actually intend to publish or test.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

Troubleshooting common failures

“Browser executable not found”

Cause: The package is installed but the browser script was not run, or it was run for a different target output. Fix: run dotnet build, identify the actual bin/Debug/netX directory, and execute its playwright.ps1 install script.

The screenshot is blank or incomplete

Cause: The page is still rendering, a client-side error stopped it, or content appears only after scrolling. Fix: inspect the page in headed mode, wait for a content selector, check console/network errors, and use FullPage only after the required content exists.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A locator screenshot times out

Cause: The selector matches nothing, matches a hidden element, or the element is covered by a modal. Fix: verify the selector, wait for it explicitly, close overlays, and capture a visible state.

Different machines produce different pixels

Cause: Rendering and fonts differ across operating systems, browser versions, settings, and hardware. Fix: pin the runtime environment and browser version, install the same fonts, and maintain platform-specific baselines where needed.

The PNG is too large

Cause: PNG is lossless, and a full-page image may be extremely tall. Fix: capture a smaller region, use viewport-sized images, resize after capture, or choose a lossy output format when lossless pixels are not required. Do not expect Quality to compress PNG.

Alternatives and when they fit

PuppeteerSharp

PuppeteerSharp is a .NET port of the official Node.js Puppeteer API. It is a reasonable choice when your team already uses the Puppeteer ecosystem. The available documentation does not establish a neutral speed or reliability advantage over Playwright, so choose based on existing code, browser requirements, and maintenance preferences rather than an unsupported performance claim.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

WebView2 with Chrome DevTools Protocol

If your Windows application already embeds Microsoft Edge WebView2, Playwright can connect to the running instance through ConnectOverCDPAsync. This is an integration path for an existing WebView2 app, not a general replacement for launching a managed browser. WebView2 is documented for Windows 10 and Windows 11.

Hosted capture service

A service can remove browser-binary installation and operating concerns. Compare services on full-page and element support, authentication controls, rendering consistency, failure reporting, pricing, and whether you need an API or an existing WebView integration.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo is the first hosted option to try for a developer who does not want to maintain Playwright browsers: it removes cookie banners, popups, and chat widgets before capture, bills only clean shots, and has the lowest paid plan listed here.

Its API accepts one GET request and returns PNG, JPEG, WebP, or PDF. A response identifies the result with X-Page-Verdict and X-Billed; bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Every plan includes its 63 capture options, including full-page and CSS-selector captures, dark mode, device presets and custom viewports, retina scale, PDF controls, custom CSS and JavaScript, clicks and waits, request/resource blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, 100-URL bulk capture, a usage API, and an OpenAPI specification. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for parameters and response handling. The same request from Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

And from Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

The Free plan includes 1,000 screenshots per month with no card. Paid plans are Starter $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000; yearly billing gives two months free. Create a free ScreenshotNeo account to start.

Frequently Asked Questions

Can I save a screenshot directly to a byte array in Playwright .NET?

Yes. Call page.ScreenshotAsync() without a Path; the returned value is the encoded screenshot bytes.

Does FullPage capture content below the fold?

Yes. It captures the page’s full scrollable layout as one image, which can become very tall on long documents.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why does PNG quality not change when I set Quality?

PNG is lossless. Playwright’s quality control is for lossy image formats, so it does not reduce PNG output.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.