Use Playwright’s Page API: launch a browser, open a page, navigate to the target URL, then call await page.screenshot({ path: 'screenshot.png' }). The file is written when the promise resolves. Add fullPage: true for the entire scrollable page, omit path to receive an image Buffer, or call screenshot() on a locator to capture one element.
The smallest working Node.js example
This CommonJS script captures the visible viewport of https://example.com and saves it as screenshot.png. It assumes Playwright and the selected browser have already been installed in your project.
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();
})();
Replace chromium with firefox or webkit when you need to capture in another browser engine. Keep the browser close in a finally block in production code so a navigation or screenshot error does not leave a process running.
Prepare the project without hard-coding stale versions
Add Playwright to your Node.js project with the package manager and browser-install steps documented for the Playwright release you are using. Browser binaries and supported Node.js versions can change, so verify those details against the current Playwright setup guidance rather than copying an old version pin. The code above is deliberately independent of a particular Playwright version.
#1 Best Overall
Run the script from the directory in which you want the image. A relative path is resolved from Node’s current working directory, not from the JavaScript file’s directory. Create the destination directory first if it does not exist.
Viewport, full-page, and element screenshots
Capture the current viewport
page.screenshot() captures what is visible in the page viewport by default. This is the right choice for a browser-like snapshot at a known width and height.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
await page.goto('https://example.com');
await page.screenshot({ path: 'viewport.png' });
await browser.close();
})();
Capture the complete scrollable page
Set fullPage: true when the output should include content below the fold.
await page.screenshot({
path: 'full-page.png',
fullPage: true
});
The viewport width remains the width you configured; Playwright extends the capture vertically to include the page’s scrollable content. Very tall pages produce large images, so use a viewport capture when a single screen is all you need.
Recommended Free Tools
Capture one element
Use a locator instead of the discouraged ElementHandle screenshot API. Locator screenshots wait for the target to be actionable and scroll it into view before capturing it.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
const card = page.locator('.pricing-card');
await card.screenshot({ path: 'pricing-card.png' });
The element must exist and be visible in the rendered page. If the target is inside a scrollable container, the screenshot contains the portion currently exposed by that container; it does not automatically turn the container into an infinite full-page image.
Save an image file or keep the image in memory
Write directly to disk
Pass path to save the result. The output format is inferred from the filename extension, so use .png, .jpg or .jpeg, or .webp when that format is supported by your Playwright version.
await page.screenshot({ path: 'artifacts/home.webp' });
Return a Buffer
Omit path when another Node.js API should receive the bytes, such as an object-storage client, a test attachment, or an image-processing library.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteconst image = await page.screenshot({ type: 'png' });
console.log(`captured ${image.length} bytes`);
A returned Buffer avoids an intermediate file. If you need a file later, write it with Node’s filesystem API after the screenshot promise resolves.
Choose format, quality, pixel scale, and background
PNG, JPEG, and WebP
PNG is the default. JPEG and WebP can be selected with type. The quality option applies to JPEG and WebP; it has no effect on PNG.
Rank #3
await page.screenshot({
path: 'compressed.jpg',
type: 'jpeg',
quality: 82
});
await page.screenshot({
path: 'compressed.webp',
type: 'webp',
quality: 80
});
Use PNG for crisp text, transparency, or pixel-sensitive comparisons. Use JPEG or WebP when a smaller photographic or web-delivery asset matters more than lossless pixels.
CSS pixels versus device pixels
The scale option controls output density. scale: 'css' produces one output pixel per CSS pixel. scale: 'device' uses device pixels and is the Page API default, so high-DPI contexts can create a larger image.
Free tools Windows power users keep installed
One-click scans. No signup required.
await page.screenshot({
path: 'css-scale.png',
scale: 'css'
});
Choose one scale and keep it fixed for visual comparisons. Changing it changes the image dimensions even when the page itself has not changed.
Transparent output
omitBackground: true hides the default white background, which is useful for PNG overlays. It does not apply to JPEG, whose format cannot preserve transparency.
await page.screenshot({
path: 'logo-overlay.png',
omitBackground: true
});
Make captures repeatable on animated pages
Animations and asynchronous rendering are common reasons two captures differ. For a locator screenshot, animations: 'disabled' stops CSS and Web Animations while the image is taken.
Rank #4
- 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
await page.locator('.hero').screenshot({
path: 'hero-static.png',
animations: 'disabled'
});
The locator API also supports a temporary style value for screenshot-specific CSS. Use it to hide a blinking cursor, freeze a transition, or remove a decoration that is irrelevant to the artifact, without changing the page permanently.
await page.locator('.dashboard').screenshot({
path: 'dashboard.png',
animations: 'disabled',
style: '* { transition: none !important; animation: none !important; }'
});
Navigate before capturing and wait for the content your image actually needs. A successful goto only proves that navigation reached its chosen completion point; a client-rendered dashboard may still be filling in after that. Waiting for a meaningful locator is more reliable than adding an arbitrary long delay.
A production-friendly capture function
This version returns a Buffer, closes the browser even when navigation fails, and exposes the main choices to its caller.
const { chromium } = require('playwright');
async function capture(url, options = {}) {
const browser = await chromium.launch();
try {
const page = await browser.newPage({
viewport: options.viewport || { width: 1365, height: 768 }
});
await page.goto(url);
return await page.screenshot({
type: options.type || 'png',
fullPage: Boolean(options.fullPage),
scale: options.scale || 'css',
omitBackground: Boolean(options.omitBackground)
});
} finally {
await browser.close();
}
}
(async () => {
const image = await capture('https://example.com', { fullPage: true });
require('node:fs').writeFileSync('example.png', image);
})();
Use an explicit output name when the format matters. In a service, also validate user-supplied URLs, set an execution timeout at the job boundary, and limit concurrent browsers so a queue cannot exhaust memory.
Keep ordinary captures separate from Playwright Test artifacts
The Page API is for an application, script, or one-off artifact. Playwright Test has separate screenshot workflows:
Best Value
- Automatic failure images: in the test configuration,
use: { screenshot: 'only-on-failure' }captures screenshots only when a test fails. Other documented modes includeoff,on, andon-first-failure. - Visual assertions:
await expect(page).toHaveScreenshot('page.png')belongs to the Playwright Test runner. It waits for two consecutive screenshots to stabilize before comparing them with the expected image. - Attachments: a Buffer can be attached to a test report with
testInfo.attach('screenshot', { body: screenshot, contentType: 'image/png' }).
Do not add test-runner configuration merely to save a screenshot from a utility script. Conversely, do not replace a visual assertion with a manually saved image when the goal is regression detection.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshooting common failures
| Symptom | Likely cause | Fix |
|---|---|---|
Cannot find module 'playwright' |
The dependency is not installed in the project from which Node is running. | Install Playwright in that project and rerun the script from the same working directory. |
| Browser executable is missing | The Playwright package is present but its browser binary has not been installed, or a custom executable path is invalid. | Run the browser-install step required by your Playwright release, or remove the invalid custom path. |
| Navigation times out or never reaches the intended page | The URL is unavailable, redirects indefinitely, requires authentication, or the chosen navigation completion condition is unsuitable. | Check the URL from the same machine, handle authentication explicitly, and inspect the final page URL before taking the image. |
| Image is blank or shows a loading shell | The screenshot ran before client-side content rendered. | Wait for a locator that represents the finished content, then capture that page or locator. |
| Only the visible part of a long page appears | Viewport capture is the default. | Add fullPage: true. |
| Element screenshot fails because the target is not found | The selector is wrong, the element is inside a frame, or it is created only after an interaction. | Confirm the selector in the rendered DOM, target the correct frame, and perform the required interaction before locating it. |
| Element image is clipped | The element is covered, not visible, or sits in a scrollable container. | Make the element visible, remove overlays, and remember that a scrollable container captures its currently exposed content. |
| Transparent output is still opaque | JPEG cannot carry an alpha channel. | Use PNG with omitBackground: true. |
| Visual comparisons change between runs | Animations, device-pixel scaling, fonts, time, or remote data changed. | Fix the viewport and scale, disable animations for the capture, wait for stable content, and control other environment-dependent inputs. |
Performance, reliability, and cost decisions
- Reuse a browser when capturing many URLs: launching a fresh browser for every image adds startup work. Keep a controlled browser process and create isolated pages when your workload permits.
- Prefer viewport images for previews: full-page images can become very tall and consume more memory and storage.
- Use buffers for pipelines: skip temporary files when the next step uploads or transforms the image.
- Make output deterministic: pin viewport dimensions, format, quality, scale, and animation behavior in the job definition.
- Plan for failures: close pages and browsers in cleanup code, record the target URL and final URL, and retry only failures that are plausibly transient.
- Local cost: Playwright itself does not charge per screenshot; your costs are the machine time, browser memory, storage, and any hosted browser infrastructure you choose.
Or skip the browser setup
If you only need a clean image from a URL, ScreenshotNeo provides a website screenshot API and MCP server. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the result with X-Page-Verdict and X-Billed headers.
Use the one-call API documented at https://screenshotneo.com/docs/:
curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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}`);
ScreenshotNeo also supports full-page and CSS-selector captures, dark mode, device presets and custom viewports, retina scale, PDF output, custom CSS and JavaScript, pre-capture clicks, selector waits and delays, network-idle waits, ad and tracker blocking, custom headers, cookies, user agents and Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable 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 familiar parameter names for easier migration.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to 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 screenshots. Create a free ScreenshotNeo account to try it without a card.
Frequently Asked Questions
Does fullPage change the browser viewport width?
No. It keeps the page width and extends the capture vertically across the scrollable document. Set the viewport explicitly when the rendered width matters.
Should I use a locator screenshot or a page screenshot for a component?
Use a locator when the artifact is one visible component; use a page screenshot when surrounding layout, overlays, and viewport context are part of what you need to inspect.
Can a Buffer be used without writing a PNG first?
Yes. Omitting path returns a Node.js Buffer that can be uploaded, attached to a test report, or transformed directly.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →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.

