Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11The core syntax is await page.screenshot({ path: 'screenshot.png' }). It captures the current viewport and returns an image buffer; supplying path writes the file, with the format inferred from the extension. Add fullPage: true for the entire scrollable document, use a locator’s screenshot() method for one element, or provide clip for a rectangular region.
Start with a runnable Playwright screenshot
Install Playwright, install at least one browser, then create a script such as screenshot.js:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
await browser.close();
})();
Run it with node screenshot.js. The relative path is resolved from the process’s current working directory. If you omit path, Playwright still captures the image and returns it as a buffer, which is useful when an application uploads the bytes instead of writing a local file. Chromium is used above; the same Page API works with Firefox and WebKit when you launch those browser types.
Choose the area to capture
Viewport screenshot
Leave out fullPage to capture only what is currently visible in the viewport:
Recommended Free Tools
#1 Best Overall
await page.screenshot({ path: 'viewport.png' });
Full-page screenshot
Set fullPage: true to capture the document’s complete scrollable height rather than just the viewport:
await page.screenshot({
path: 'full-page.png',
fullPage: true
});
Full-page capture is based on the page’s scrollable content. Pages that render content only after scrolling may need an explicit scroll or a wait for the relevant content before the screenshot. Fixed headers, sticky widgets, and animated sections can also appear repeatedly or at different positions unless you stabilize them.
Rectangular clipping
Use clip with x, y, width, and height to capture a region in page coordinates:
await page.screenshot({
path: 'region.png',
clip: { x: 120, y: 180, width: 640, height: 360 }
});
The rectangle must be valid for the page. For responsive layouts, a locator is generally more robust than hard-coded coordinates because it follows the element when the layout changes.
Element or component screenshot
Locator screenshots wait for the target’s actionability checks and scroll it into view before capturing it. Prefer a locator over the discouraged ElementHandle.screenshot() form:
const button = page.getByRole('button', { name: 'Subscribe' });
await button.screenshot({ path: 'subscribe-button.png' });
const card = page.locator('[data-testid="pricing-card"]');
await card.screenshot({ path: 'pricing-card.webp', type: 'webp' });
A covered element is not magically exposed: if another element occludes it, the captured pixels show the covering content. For a scrollable container, the image contains the portion currently visible inside that container, not all of its off-screen children. Scroll the container first when you need a particular subsection.
Rank #2
Control format, scale, and quality
| Option | Use | Example |
|---|---|---|
type |
Select PNG, JPEG, or WebP. | type: 'jpeg' |
path |
Write the result to a file; the extension also infers the type. | path: 'page.webp' |
quality |
Set lossy JPEG/WebP quality. It does not apply to PNG. | quality: 80 |
scale |
Choose CSS-pixel or device-pixel output where supported. | scale: 'css' |
omitBackground |
Use transparency instead of an opaque background where supported. | omitBackground: true |
fullPage |
Capture the complete scrollable page. | fullPage: true |
clip |
Capture a coordinate rectangle. | clip: { x: 0, y: 0, width: 400, height: 300 } |
PNG is the documented default. Use JPEG or WebP when smaller files matter and transparency is unnecessary. Set quality only for lossy formats. The exact pixel dimensions also depend on the browser context’s viewport and device scale factor.
Viewport and retina output
const context = await browser.newContext({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 2
});
const page = await context.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'retina.png', scale: 'device' });
A larger device scale factor produces more physical pixels and larger files. Keep viewport, browser engine, fonts, and scale fixed when screenshots are used for visual comparisons.
Free tools Windows power users keep installed
One-click scans. No signup required.
Make screenshots deterministic
Wait for the page state you actually need
Navigation finishing does not guarantee that a chart, image, or client-rendered component is ready. Wait for a selector, a known state, or a bounded delay:
await page.goto('https://example.com/dashboard', { waitUntil: 'domcontentloaded' });
await page.locator('[data-testid="chart"]').waitFor({ state: 'visible' });
await page.screenshot({ path: 'dashboard.png' });
A selector wait is preferable to an arbitrary sleep. Use a short delay only when an application has a known, unavoidable transition that cannot expose a reliable ready state.
Disable motion and hide unstable content
Animated cursors, carousels, clocks, and rotating advertisements can make two captures differ. Inject a screenshot-only stylesheet and mask dynamic regions:
await page.screenshot({
path: 'stable.png',
animations: 'disabled',
mask: [
page.locator('[data-testid="live-clock"]'),
page.locator('.personalized-recommendations')
],
style: `
*, *::before, *::after {
animation: none !important;
transition: none !important;
caret-color: transparent !important;
}
`
});
The injected style affects the screenshot without requiring you to alter the application’s normal stylesheet. Masking replaces the selected regions with a solid mask so volatile values do not create false visual differences. Choose selectors that are present before capture; otherwise wait for them first.
Set the environment explicitly
const context = await browser.newContext({
viewport: { width: 1280, height: 800 },
colorScheme: 'dark',
locale: 'en-US',
timezoneId: 'UTC'
});
Use a fixed viewport, color scheme, locale, timezone, and browser engine for repeatable output. If the page depends on authentication, create the context with the required storage state or log in before capturing. Keep test data stable as well; a screenshot can be perfectly deterministic while still reflecting different backend data on each run.
Use screenshots in Playwright Test
Visual assertions
For visual regression tests, use expect(page).toHaveScreenshot() rather than manually writing files:
import { test, expect } from '@playwright/test';
test('home page matches the baseline', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveScreenshot('home.png', {
fullPage: true,
animations: 'disabled',
mask: [page.locator('.live-status')]
});
});
Playwright Test compares the new image with a stored baseline and reports visual differences. Keep the project’s browser, viewport, and screenshot settings consistent between baseline creation and CI runs. Review intentional UI changes and update baselines deliberately rather than accepting every diff.
Automatic screenshots after tests
Configure the test runner to save screenshots after a test finishes, according to its result:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #4
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
screenshot: 'only-on-failure'
}
});
This is useful for diagnosing failures without producing an image for every successful test. Other supported policies can capture screenshots for every test or after each test step; choose the least noisy policy that still gives your team the evidence it needs.
Complete capture examples
Save a full-page WebP with a wait and custom viewport
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const context = await browser.newContext({
viewport: { width: 1366, height: 768 },
deviceScaleFactor: 1
});
const page = await context.newPage();
await page.goto('https://example.com/articles', { waitUntil: 'networkidle' });
await page.locator('main').waitFor({ state: 'visible' });
await page.screenshot({
path: 'articles.webp',
type: 'webp',
quality: 82,
fullPage: true,
animations: 'disabled'
});
await browser.close();
})();
networkidle can be unsuitable for applications with continuous polling or analytics requests. In that case, use a specific readiness locator and avoid waiting forever for an idle network.
Capture the returned buffer
const image = await page.screenshot({ type: 'png' });
// image is a Buffer; upload it, return it from an endpoint, or write it yourself.
require('node:fs').writeFileSync('buffer-capture.png', image);
Common failures and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Browser executable is missing | Playwright package is installed but browser binaries are not. | Run the Playwright browser installation command for the engines you use, then rerun the script. |
| Screenshot is blank or before content appears | The script captured before client rendering or a required selector was ready. | Wait for a visible, application-specific locator; verify navigation and authentication. |
| Element screenshot shows another panel | The target is covered by an overlay or modal. | Dismiss the overlay, wait for it to be hidden, or choose the intended visible locator. |
| Only part of a long list appears | The list is inside a scrollable container. | Scroll that container to the required position; a full-page screenshot does not expand an independently scrolling element. |
| Images or fonts differ in CI | Resources, fonts, browser versions, or device scale differ. | Pin the environment, wait for critical resources, and use the same browser project for baseline and comparison. |
| Full-page capture times out | The page keeps loading, has very large content, or contains a request that never settles. | Use a bounded readiness wait, investigate the hanging resource, reduce capture scope, or increase the operation timeout intentionally. |
| JPEG quality has no effect | Quality is unsupported for PNG. | Set type: 'jpeg' or type: 'webp' before setting quality. |
| Visual test fails with tiny differences | Animation, time, random data, or responsive dimensions changed. | Disable motion, mask dynamic areas, freeze test data, and standardize viewport, locale, timezone, and scale. |
Performance, reliability, and file strategy
- Capture only what you need. Viewport and element images are normally cheaper in time and memory than very tall full-page images.
- Reuse a browser process. Launching a browser for every URL adds startup overhead; create contexts and pages within one controlled process when capturing batches.
- Bound waits. A selector wait with a sensible timeout fails clearly; an unrestricted network-idle wait can hang on apps that poll continuously.
- Control concurrency. Running too many pages at once increases CPU, memory, and resource contention. Start with a small worker count and measure in your own environment.
- Keep artifacts identifiable. Include the route, viewport, browser project, and commit or build identifier in filenames so a failed comparison can be reproduced.
- Protect secrets. Do not put access tokens, passwords, or private customer data into screenshot paths, test titles, or uploaded artifacts.
Or skip the browser setup
If you need a screenshot from a URL rather than browser automation in your own process, ScreenshotNeo provides a website screenshot API and MCP server. A single GET request returns PNG, JPEG, WebP, or a PDF:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
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)
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}`);
See the ScreenshotNeo documentation for request options. Before capture it can accept cookie or consent banners and remove 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 report the page verdict and whether the request was billed. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
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 →ScreenshotNeo includes full-page capture with lazy-image loading, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, pre-capture clicks, selector or network-idle waits, ad/tracker/request blocking, custom headers and cookies, user-agent and Authorization settings, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, an OpenAPI specification, and compatibility with parameter names used by other screenshot APIs.
| Plan | Monthly screenshots | Price |
|---|---|---|
| Free | 1,000 | $0, no card |
| Starter | 3,000 | $5 |
| Growth | 15,000 | $15 |
| Pro | 60,000 | $39 |
| Scale | 250,000 | $99 |
| Business | 1,000,000 | $249 |
Every feature is available on every plan, and yearly billing provides two months free. Create a free ScreenshotNeo account to get 1,000 screenshots a month with no card.
Playwright screenshot syntax FAQ
What does page.screenshot() return?
It returns a buffer containing the encoded image. When you pass path, Playwright also writes that image to the specified file.
Can I screenshot a PDF with Playwright’s screenshot method?
No. page.screenshot() creates an image. Use a PDF-capable workflow when the required output is a PDF, or use ScreenshotNeo’s capture_pdf MCP tool or PDF options for URL-based capture.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesWhy is a locator screenshot preferable to an element handle?
Locators include Playwright’s actionability and auto-wait behavior and are the recommended element-capture interface; the ElementHandle screenshot API is discouraged.
How do I make a screenshot test useful in CI?
Keep browser, viewport, scale, fonts, locale, timezone, and test data consistent; disable animation and mask volatile regions; then review baseline changes as code changes rather than accepting every diff automatically.
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.

