Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCapture the screenshot in your test runner’s cleanup hook, after checking that the test failed. Use Page.ScreenshotAsync for a single final-state image. If you need the actions, DOM snapshots, network activity and source context that led to the failure, start Playwright tracing before the test and save the trace only when cleanup detects a failure.
The exact hook and result property depend on whether you use NUnit, MSTest, xUnit or xUnit v3. The lifecycle below is deliberately explicit so you can adapt it to your installed Playwright .NET and runner versions without relying on a brittle, universal snippet.
Choose the artifact you actually need
| Need | Use | What you get |
|---|---|---|
| A quick visual of the final page | Page.ScreenshotAsync |
PNG, JPEG or WebP image written to a path or returned as bytes. |
| The whole scrollable page | Screenshot with FullPage = true |
A tall image containing the page beyond the viewport. |
| One component | Locator or element screenshot | An image cropped to the selected element. |
| The sequence that caused the failure | Context.Tracing |
A trace archive with a visual filmstrip, DOM snapshots, action and network context, console data and errors, depending on enabled options. |
A screenshot is a final-state artifact; it cannot show an earlier redirect, click, request or assertion. Tracing records browser operations and network activity, but the low-level tracing API does not record test assertions itself. For assertion-level context, use the runner-aware tracing configuration documented for your framework.
Prepare a reliable artifact directory
Create an output directory before the test runs and make every filename unique. Parallel workers can execute tests simultaneously, so a plain name such as failure.png can be overwritten. A sanitized test name plus a run, worker or GUID component is an engineering safeguard, not a Playwright guarantee.
#1 Best Overall
using System.Text.RegularExpressions;
static string SafeName(string value)
{
var name = Regex.Replace(value, @"[^A-Za-z0-9._-]+", "_");
return string.IsNullOrWhiteSpace(name) ? "test" : name;
}
static string ArtifactPath(string testName, string extension)
{
var root = Path.Combine(AppContext.BaseDirectory, "artifacts");
Directory.CreateDirectory(root);
var unique = $"{DateTime.UtcNow:yyyyMMdd-HHmmssfff}-{Environment.CurrentManagedThreadId}-{Guid.NewGuid():N}";
return Path.Combine(root, $"{SafeName(testName)}-{unique}.{extension}");
}
Keep paths short enough for your operating system and CI runner. If your CI system already supplies a job, worker or retry identifier, include it in the filename or directory. Upload artifacts only to storage with appropriate access controls and retention rules: screenshots and traces can expose credentials, tokens, source code and application data.
Minimal C# pattern: screenshot in teardown
The essential sequence is:
- Run the test normally.
- In cleanup, inspect the runner’s result.
- If it failed, call
Page.ScreenshotAsyncwith a unique path. - Dispose the page and context according to your runner integration.
The following method is reusable from any runner hook once you provide the runner’s test name and failure Boolean.
using Microsoft.Playwright;
static async Task SaveFailureScreenshotAsync(
IPage page,
string testName,
bool failed,
bool fullPage = false)
{
if (!failed)
return;
var path = ArtifactPath(testName, "png");
await page.ScreenshotAsync(new PageScreenshotOptions
{
Path = path,
FullPage = fullPage,
Type = ScreenshotType.Png
});
Console.WriteLine($"Failure screenshot: {path}");
}
ScreenshotAsync can also return image bytes if you want to attach them through a test framework API rather than write a file:
var bytes = await Page.ScreenshotAsync(new PageScreenshotOptions
{
Type = ScreenshotType.Png,
FullPage = true
});
await File.WriteAllBytesAsync(ArtifactPath(testName, "png"), bytes);
Capture after the assertion has failed but before the page or context is disposed. If cleanup closes the browser first, there is no live page from which to capture.
Free tools Windows power users keep installed
One-click scans. No signup required.
NUnit: screenshot and trace on failure
Playwright .NET’s NUnit integration supplies the page, context and lifecycle. In a real project, use the NUnit failure property exposed by your installed NUnit version and Playwright base class. The names below show the lifecycle, while the result lookup is intentionally isolated so you can match your package version.
using Microsoft.Playwright.NUnit;
using NUnit.Framework;
public class CheckoutTests : PageTest
{
[SetUp]
public async Task StartDiagnostics()
{
await Context.Tracing.StartAsync(new TracingStartOptions
{
Title = TestContext.CurrentContext.Test.Name,
Screenshots = true,
Snapshots = true,
Sources = true
});
}
[Test]
public async Task CheckoutShowsConfirmation()
{
await Page.GotoAsync("https://example.test/checkout");
await Page.GetByRole(AriaRole.Button, new() { Name = "Pay" }).ClickAsync();
await Expect(Page.GetByText("Confirmation")).ToBeVisibleAsync();
}
[TearDown]
public async Task SaveDiagnostics()
{
// Use the failure-status property provided by your NUnit/Playwright version.
var failed = TestContext.CurrentContext.Result.Outcome.Status
== NUnit.Framework.Interfaces.TestStatus.Failed;
var name = TestContext.CurrentContext.Test.Name;
var tracePath = failed ? ArtifactPath(name, "zip") : null;
// Saving a path writes the trace; omitting it discards the successful trace.
await Context.Tracing.StopAsync(new TracingStopOptions { Path = tracePath });
await SaveFailureScreenshotAsync(Page, name, failed);
}
}
Verify the exact status enum and base class against the versions installed in your solution. Some runners report skipped, inconclusive or setup failures differently. Decide whether those states should produce artifacts and encode that policy in the Boolean rather than treating every non-passing state as an assertion failure.
MSTest, xUnit and xUnit v3
Playwright provides runner integrations for MSTest, NUnit, xUnit and xUnit v3. They create a new browser context per test while reusing Playwright and browser instances. Use the official Trace Viewer example matching your framework, then place the same two operations in its cleanup hook:
- Determine the framework’s result for the current test.
- Stop tracing with a path only for a failed test, and call
Page.ScreenshotAsynconly for that test.
Do not copy an NUnit result expression into MSTest or xUnit. Cleanup ordering, async hook attributes and failure properties differ, and a setup failure may occur before a page exists. For a setup failure, record whatever artifact your runner can create (for example, a test log) and avoid dereferencing a null page.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
When assertions must appear in the trace
Start tracing through the runner-aware configuration when available. The bare context.tracing API captures browser operations and network activity but not assertion events. Runner integration can add test and assertion context that makes a trace easier to interpret.
Tracing options that matter
await Context.Tracing.StartAsync(new TracingStartOptions
{
Title = testName,
Screenshots = true, // visual timeline
Snapshots = true, // DOM snapshots and related activity
Sources = true // source files and locations where supported
});
- Screenshots: adds the filmstrip shown in Trace Viewer.
- Snapshots: records DOM state and network-related context around actions.
- Sources: includes source material, which helps connect an action to test code but increases sensitivity and artifact size.
Stop a trace with Path on failure and without a saved path on success. Playwright’s CI guidance recommends recording traces for failing tests only. This reduces storage and avoids routinely retaining sensitive page data.
var tracePath = failed ? ArtifactPath(testName, "zip") : null;
await Context.Tracing.StopAsync(new TracingStopOptions { Path = tracePath });
Open the resulting archive with Playwright Trace Viewer. Its static browser viewer loads a trace in the browser without transmitting it to an external service, but the archive still needs protection wherever your CI stores or distributes it.
Full-page, element and post-processing captures
Full page
await Page.ScreenshotAsync(new PageScreenshotOptions
{
Path = ArtifactPath(testName, "png"),
FullPage = true
});
Full-page output can be very tall and expensive to store. Prefer the viewport image when the failure is visible above the fold, and use full-page capture for layout, document or responsive regressions.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Rank #3
One element
var card = Page.Locator("[data-testid='order-summary']");
await card.ScreenshotAsync(new LocatorScreenshotOptions
{
Path = ArtifactPath(testName + "-summary", "png")
});
An element screenshot is useful when the page contains dynamic headers, cookie prompts or unrelated content. Ensure the locator resolves and is visible before capture; otherwise cleanup can hide the original failure with a second timeout.
Wait before capture
A failed assertion may leave an animation or navigation in progress. If the page is still usable, wait for a stable selector or a short, bounded delay in the test itself. Avoid long waits in teardown: cleanup should preserve evidence quickly and should not turn one failure into a teardown timeout.
Non-runner applications and custom frameworks
Install the Microsoft.Playwright package and the Playwright browsers using the installation command documented for your .NET project. Create the browser, context and page in your application, then wrap the test body in a try/catch/finally structure. The catch block can set failed = true; the finally block saves the screenshot and stops the trace before disposing the context.
bool failed = false;
var testName = "custom-check";
await using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
{
Headless = true
});
var context = await browser.NewContextAsync();
var page = await context.NewPageAsync();
try
{
await context.Tracing.StartAsync(new TracingStartOptions
{
Title = testName, Screenshots = true, Snapshots = true, Sources = true
});
await page.GotoAsync("https://example.test");
// application assertions and actions
}
catch
{
failed = true;
throw;
}
finally
{
var trace = failed ? ArtifactPath(testName, "zip") : null;
await context.Tracing.StopAsync(new TracingStopOptions { Path = trace });
await SaveFailureScreenshotAsync(page, testName, failed);
await context.CloseAsync();
}
Guard the finally block if navigation or browser startup failed before page or tracing became available. In a custom framework, preserve the original exception even if artifact capture also fails.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsCommon failures and fixes
No screenshot appears
- Confirm the runner’s failure Boolean is true for the state you are testing.
- Check that cleanup runs after the assertion and before page disposal.
- Print the resolved path and verify the CI job uploads that directory.
Teardown throws a second timeout
- Use a short, bounded cleanup path; do not wait indefinitely for a selector.
- Check that the page and context are still open.
- Wrap artifact capture so the original test exception remains the reported failure.
Files overwrite one another
Add a sanitized test identifier plus GUID, timestamp, worker or retry value. Parallel execution makes fixed filenames unsafe.
Trace is empty or cannot be opened
- Start tracing before the actions you need to inspect.
- Stop tracing exactly once and provide a writable file path only on failure.
- Ensure the CI process has permission to create the directory and archive.
The trace lacks assertion details
Use the runner-aware tracing setup rather than relying solely on low-level context tracing. The low-level API does not record assertions.
Artifacts contain secrets
Redact or avoid sensitive test data, restrict artifact permissions, encrypt storage where appropriate and set a retention period. Treat source-enabled traces as source-code exports.
Performance, reliability and cost decisions
- Recording screenshots and snapshots adds work during the test, so enable it for diagnostics rather than every successful run.
- Saving only failed traces follows Playwright’s CI recommendation and limits storage.
- Use PNG when pixel fidelity matters; choose another supported image type when file size is more important and your review tooling accepts it.
- Keep screenshot and trace paths inside the CI artifact workspace so the runner can collect them on retries and parallel workers.
- Do not assume a screenshot proves the browser reached a valid application state. A blank page, bot check or failed resource load may be the actual failure; the trace and console/network context help distinguish those cases.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. For a one-off image, send one GET request; it can return PNG, JPEG or WebP, and it also supports PDF output. The API accepts the URL directly, so your C# test or CI job can call it after deciding that a test failed.
using System.Net.Http;
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(90) };
var url = "https://example.test/checkout";
var endpoint = "https://api.screenshotneo.com/v1/shot" +
"?access_key=YOUR_API_KEY&url=" +
Uri.EscapeDataString(url);
var bytes = await http.GetByteArrayAsync(endpoint);
await File.WriteAllBytesAsync("checkout-failure.webp", bytes);
For complete parameters, response headers and the MCP tools, see the ScreenshotNeo documentation. Before the shot, ScreenshotNeo accepts cookie or consent banners as a visitor 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 the response reports the page verdict and billing result in X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info and capture_pdf for Claude, Cursor and other MCP clients.
You can also use full-page capture with lazy images loaded, a CSS-selector element capture, device and viewport presets, dark mode, retina scale, custom CSS or JavaScript, clicks before capture, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API and an OpenAPI specification. Existing integrations can use the parameter names used by other screenshot APIs.
The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; higher plans are 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, and every feature is on every plan. Create a free ScreenshotNeo account to start without a card.
FAQ
Should I save a screenshot for a skipped test?
Usually no. Treat skipped and inconclusive outcomes as a separate policy; capture them only when they represent an environment problem you need to investigate.
Can a screenshot replace a Playwright trace?
No. It shows one rendered state, while a trace can show the sequence, snapshots and browser context that preceded it.
Best Value
What if the failure happens before a page is created?
Do not call ScreenshotAsync on a missing page. Record the runner log and guard cleanup for null or disposed browser objects.
Where should CI artifacts be stored?
Use trusted, access-controlled artifact storage with retention appropriate to credentials, source and user data that may appear in images or traces.
Frequently Asked Questions
Does Playwright automatically take a screenshot when a C# test fails?
No. Add a runner cleanup hook that checks the test result and calls Page.ScreenshotAsync, or configure the matching runner integration.
Recommended Free Tools
What is the simplest failure artifact?
A unique path passed to Page.ScreenshotAsync in teardown after confirming the test failed.
How do I inspect actions before the failure?
Start tracing before test actions with screenshots and snapshots enabled, then stop it with a path only when cleanup detects failure.
The Bottom Line
Use Page.ScreenshotAsync for a final image and runner-aware tracing for the timeline behind a failure. Check the result before cleanup, create unique artifact paths, preserve the original exception, and protect uploaded files.
Quick Recap
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.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →

