October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
ASP.NET Core

Capturing a Screenshot of a Webpage in ASP.NET Core with Playwright

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

The most direct way to capture a webpage in ASP.NET Core is to use Microsoft.Playwright: launch a browser, open a page, navigate to the URL, and call ScreenshotAsync. Use FullPage = true for the entire scrollable document, Locator.ScreenshotAsync for one element, a file path when you want the browser to write an image, or the returned byte[] when your API should stream the result.

This guide builds that workflow into an ASP.NET Core service, explains viewport and full-page capture, shows PNG/JPEG/WebP and deterministic-rendering options, and covers the failure modes that matter in a web application.

What you need

  • A supported .NET SDK and an ASP.NET Core application.
  • The Microsoft.Playwright NuGet package.
  • Playwright browser binaries installed for the target .NET output. The official library guide describes creating a console project, adding the dependency, building, and running the generated Playwright browser-install script: Playwright .NET library setup.

Playwright’s project documentation describes one API for Chromium, Firefox, and WebKit. If your application only needs Chrome or Chromium, PuppeteerSharp is another .NET option and documents screenshot and PDF use cases: Playwright .NET README and PuppeteerSharp on NuGet. There is no documented universal performance or reliability winner, so choose based on required browser coverage and the API that fits your codebase.

Install Playwright in an ASP.NET Core project

  1. Create or open the ASP.NET Core project that will perform the capture.
  2. Add the package:
    dotnet add package Microsoft.Playwright
  3. Build the project so the Playwright-generated browser-install script is created.
  4. Run that generated script for your target .NET output, following the current command and path shown in the official library guide. Browser binaries are separate from the NuGet package; installing the package alone does not make a browser executable available.

For a long-running web service, create browser and Playwright instances with an intentional lifecycle rather than launching a new browser for every request. The minimal example below mirrors the documented library workflow; production hosting, isolation, and resource limits require decisions specific to your deployment.

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

Minimal C# screenshot program

This console-style example saves a viewport screenshot to disk:

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

The same ScreenshotAsync call can omit Path and return image bytes. That is useful when an ASP.NET Core action should return the image without writing a temporary file.

Expose a screenshot endpoint in ASP.NET Core

The following controller launches Playwright for each request to keep the example self-contained. A service that handles substantial traffic should manage browser lifetime and concurrency deliberately, and should not assume that this small sample is a complete production isolation design.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Playwright;

[ApiController]
[Route("api/screenshots")]
public sealed class ScreenshotsController : ControllerBase
{
    [HttpGet]
    public async Task Capture(
        [FromQuery] string url,
        [FromQuery] bool fullPage = false,
        CancellationToken cancellationToken = default)
    {
        if (!Uri.TryCreate(url, UriKind.Absolute, out var target) ||
            (target.Scheme != Uri.UriSchemeHttp && target.Scheme != Uri.UriSchemeHttps))
        {
            return BadRequest("url must be an absolute HTTP or HTTPS URL.");
        }

        using var playwright = await Playwright.CreateAsync();
        await using var browser = await playwright.Chromium.LaunchAsync();
        var page = await browser.NewPageAsync();

        await page.GotoAsync(url, new PageGotoOptions
        {
            WaitUntil = WaitUntilState.Load,
            Timeout = 30_000
        });

        var bytes = await page.ScreenshotAsync(new PageScreenshotOptions
        {
            FullPage = fullPage,
            Type = ScreenshotType.Png
        });

        return File(bytes, "image/png", "screenshot.png");
    }
}

FullPage = true captures the page’s full scrollable extent, as if it were displayed on a very tall screen. With the default false, the result is the current viewport. The official screenshot reference documents the complete option set: Playwright screenshots.

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

In a real endpoint, validate and constrain the URL policy for your application, set request and navigation timeouts, and apply authentication, authorization, concurrency, and resource controls appropriate to your environment. The basic library documentation does not establish a secure design for accepting arbitrary internet URLs.

Return bytes, save a file, or capture an element

Return bytes from the page API

When no path is supplied, Page.ScreenshotAsync returns a byte[]. ASP.NET Core can send it with File(bytes, "image/png"), store it in object storage, or pass it to another image-processing step. This avoids managing a temporary filename.

Write directly to a path

await page.ScreenshotAsync(new PageScreenshotOptions
{
    Path = "artifacts/home.webp",
    Type = ScreenshotType.Webp
});

PNG, JPEG, and WebP are supported. The API’s Quality option applies to lossy JPEG and WebP output; it does not change PNG quality. Choose the MIME type and file extension consistently.

Capture one element

var card = page.Locator(".pricing-card");
var cardBytes = await card.ScreenshotAsync(new LocatorScreenshotOptions
{
    Type = ScreenshotType.Png
});

A locator screenshot performs actionability checks and scrolls the element into view. If another element covers it, the captured result may not show the target as expected. For a scrollable container, only the content currently visible in that container is captured; a locator screenshot is not automatically a screenshot of every item hidden inside the container. See the locator API reference.

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

Control dimensions, scale, and appearance

Viewport and device pixels

Create a page with an explicit viewport when visual dimensions must be repeatable:

var page = await browser.NewPageAsync(new BrowserNewPageOptions
{
    ViewportSize = new ViewportSize { Width = 1440, Height = 900 },
    DeviceScaleFactor = 1
});

CSS-pixel dimensions and device-pixel output are separate concerns. A higher device scale factor produces more physical pixels and a larger image; keep it fixed when comparing screenshots.

JPEG, WebP, clipping, and transparency

await page.ScreenshotAsync(new PageScreenshotOptions
{
    Path = "hero.jpg",
    Type = ScreenshotType.Jpeg,
    Quality = 82,
    Clip = new Clip { X = 0, Y = 0, Width = 1200, Height = 700 }
});

Clipping limits capture to a rectangle. Transparent backgrounds are available where the page screenshot options support them; transparency is meaningful for formats that preserve an alpha channel, such as PNG. JPEG cannot preserve transparency.

Reduce visual nondeterminism

The API includes an option to disable animations and an injected stylesheet option for changing or hiding dynamic elements. For example, you can freeze transitions before capture:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.ScreenshotAsync(new PageScreenshotOptions
{
    Path = "stable.png",
    Animations = ScreenshotAnimations.Disabled,
    Style = "*, *::before, *::after { animation: none !important; transition: none !important; }"
});

These controls improve repeatability, but the documentation does not guarantee application-specific determinism. Fonts, remote data, clocks, advertisements, and responsive breakpoints can still change a page.

Wait for the page you actually want

GotoAsync returning means the selected navigation condition was met; it does not prove that every image or client-rendered component has finished. Wait for a meaningful selector when the page has a known ready state:

await page.GotoAsync(url, new PageGotoOptions
{
    WaitUntil = WaitUntilState.NetworkIdle,
    Timeout = 30_000
});
await page.Locator("main[data-ready='true']").WaitForAsync(new LocatorWaitForOptions
{
    Timeout = 10_000
});

If network idle is not appropriate for a page with analytics or streaming requests, wait for a specific selector or use a bounded delay. For lazy-loaded images, full-page capture can require scrolling or page-specific readiness logic; Playwright documents the screenshot controls but does not promise that every site’s lazy-loading implementation will behave identically.

Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or a PDF, so your ASP.NET Core code does not need to install or operate Playwright browsers.

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.
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 request options and response details. The equivalent calls in Python and Node.js are:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Before capture, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up free for ScreenshotNeo.

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

Troubleshooting common failures

Browser executable is missing

Symptom: launch fails with an executable-not-found message. Cause: the NuGet package is installed but the Playwright browser-install script has not been run for the built output. Fix: build the project and run the generated script as described in the official library setup.

Navigation times out

Cause: DNS, TLS, a slow server, a page that never settles, or an overly strict timeout. Fix: verify the URL from the host running ASP.NET Core, set a bounded but appropriate Timeout, and wait for a specific ready selector instead of requiring network idle on pages with persistent connections.

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

The screenshot is blank or incomplete

Cause: capture occurred before client rendering or lazy content completed, or the requested element is covered. Fix: wait for the application’s ready selector, confirm the element is visible, and inspect whether a scrollable container is hiding the content you expected.

Full-page output is unexpectedly tall or inconsistent

Cause: expanding content, animations, responsive layout, or lazy loading changes document height during capture. Fix: set a known viewport and device scale, disable animations, hide unstable elements with an injected stylesheet, and capture only after the page’s content is stable.

JPEG quality has no effect

Cause: the output is PNG, which does not use the lossy quality setting. Fix: choose JPEG or WebP when you need a quality trade-off.

Element capture does not include all rows

Cause: the target is a scrollable container. Locator screenshots capture the currently scrolled content rather than every hidden item. Fix: capture the full page, change the component’s overflow behavior for a dedicated export view, or capture and stitch logical sections in your own application.

Free tools Windows power users keep installed

One-click scans. No signup required.

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

Operational considerations for an ASP.NET Core service

  • Browser lifecycle: launching a browser has startup cost. Reusing a controlled browser process can reduce overhead, while isolating work per context or request can limit state sharing. Select a lifecycle that matches your traffic and security requirements.
  • Concurrency: each page consumes memory and CPU. Bound simultaneous captures and return a clear overload response rather than allowing unbounded browser work.
  • Timeouts and cancellation: apply separate limits for the HTTP request, navigation, selector waits, and screenshot operation. Propagate cancellation where your hosting design permits it.
  • State: cookies, authentication headers, locale, and viewport affect pixels. Use a fresh context when captures must not share state; configure the context deliberately when a logged-in view is required.
  • Untrusted URLs: an endpoint that accepts arbitrary URLs needs an explicit allowlist or network policy, protection against access to internal services, and isolation appropriate to your infrastructure. The basic Playwright examples do not define those controls.
  • Output handling: validate format and size before storing or returning images, and set the response content type to match the selected format.

Playwright or PuppeteerSharp?

Question Playwright .NET PuppeteerSharp
Documented browser coverage Chromium, Firefox, and WebKit in the project description Chrome or Chromium
Screenshot/PDF use Documented screenshot API and related page controls Project package lists screenshots and PDF generation among uses
Best fit Applications needing one API across the documented browser engines Applications centered on Chrome/Chromium automation
Performance verdict Not established by the cited documentation Not established by the cited documentation

For a new ASP.NET Core implementation, start with Playwright when cross-browser coverage or its locator and page APIs matter. Choose PuppeteerSharp when your existing automation is built around Chrome/Chromium and its API is the better integration.

Frequently Asked Questions

Can I capture only the visible viewport instead of the whole page?

Yes. Leave FullPage unset or set it to false; the screenshot uses the current page viewport.

Does a locator screenshot capture an element that is behind a modal or overlay?

Not reliably. Locator screenshots perform visibility and actionability checks, and a covering element can prevent the target from appearing as intended.

Which output format should an API endpoint return?

Use PNG for lossless output and transparency, or JPEG/WebP when a lossy quality-size trade-off is appropriate. Set the response MIME type to match the chosen format.

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

Can Playwright capture PDFs as well as images?

The cited Playwright material for this article establishes the screenshot workflow. For PDF-specific behavior, consult the current Playwright .NET API documentation rather than assuming screenshot options apply.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

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

Read next

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.