How to Capture a Playwright Screenshot in WebKit
Launch Playwright’s WebKit browser, capture a viewport or full page, and tune the image options for stable, useful screenshots.
To capture a screenshot in WebKit with Playwright, launch Playwright’s webkit browser, open a page, navigate to the target URL, and call page.screenshot(). Install the package and its WebKit browser once, then save the result to a file:
npm install playwright
npx playwright install webkit
const { webkit } = require('playwright');
(async () => {
const browser = await webkit.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
} finally {
await browser.close();
}
})();
This captures the visible viewport as PNG. Playwright runs browsers headless by default. See the Playwright Library guide and Page API reference.
1. Install and run the WebKit example
Playwright’s package and browser binaries are separate pieces: install the package, then install WebKit. The command below works in a Node.js project. Save the JavaScript example above as screenshot.js and run node screenshot.js.
npm install playwright
npx playwright install webkit
node screenshot.js
On Linux build or CI machines, install the operating-system dependencies Playwright requires with npx playwright install-deps webkit where supported. If your project already uses Playwright Test, it may already have the package and browser installation; check the project’s installed version and setup before adding another dependency.
2. Choose what to capture
page.screenshot() captures the current viewport by default. Set options to control the region, file format, and pixel scale. The examples below assume a page has been navigated to first.
| Need | Option | Effect |
|---|---|---|
| Entire scrollable page | fullPage: true |
Captures beyond the visible viewport. |
| Specific rectangular region | clip: { x, y, width, height } |
Captures the specified rectangle in page coordinates. |
| JPEG or WebP output | type: 'jpeg' or 'webp' |
Chooses a supported image encoding. Use a matching path extension. |
| Device-pixel resolution | scale: 'device' |
Uses device pixels; output can be larger than CSS-pixel output. |
| CSS-pixel resolution | scale: 'css' |
Uses CSS pixels for output scale. |
| Stable capture around motion or focus | animations, caret, mask, style |
Controls animations, caret visibility, locator masking, and injected styles. Consult the API reference for exact option values and locator behavior. |
Full-page screenshot
await page.screenshot({ path: 'full-page.png', fullPage: true });
Full-page capture can produce a tall image and take longer than a viewport capture, especially on long pages. Pages that load content only as you scroll may need an explicit scrolling or page-specific loading step before capture; full-page mode alone does not guarantee every lazy resource has loaded.
Format and resolution
await page.screenshot({ path: 'viewport.webp', type: 'webp', scale: 'css' });
await page.screenshot({ path: 'viewport.jpeg', type: 'jpeg', quality: 80, scale: 'device' });
PNG is the default when the type is omitted. The type can also be inferred from the filename extension. JPEG quality applies to JPEG output. Device scale can increase pixel dimensions and file size, so use it when higher-resolution output is needed rather than by default.
Clipped region
await page.screenshot({
path: 'region.png',
clip: { x: 40, y: 80, width: 640, height: 360 }
});
A clip is a rectangle in page coordinates. Keep its width and height positive and within the rendered page area. If you need a semantic element rather than a coordinate rectangle, use the locator screenshot API documented by Playwright.
3. Make the capture predictable
Wait for the content you need rather than relying on an arbitrary pause. Navigation can wait for a load state, and application-specific selectors provide a stronger signal that the target content is ready.
const { webkit } = require('playwright');
(async () => {
const browser = await webkit.launch();
try {
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.locator('main').waitFor({ state: 'visible' });
await page.screenshot({ path: 'ready.png', animations: 'disabled', caret: 'hide' });
} finally {
await browser.close();
}
})();
Choose a navigation wait condition that matches the site. Waiting for every network request to stop can be unreliable on pages with analytics, streaming, or long polling. A visible application selector or a deliberate bounded delay may be more appropriate. For visual comparisons, keep the browser version, operating system, fonts, viewport, and rendering environment consistent; Playwright notes that these can change rendered output. See its visual comparison guide.
Headed mode for debugging
const browser = await webkit.launch({ headless: false });
Headed mode opens a visible browser window and is useful for inspecting navigation or page behavior. It is not required for ordinary screenshots; headless mode is the default.
4. Use screenshot assertions for visual regression
For a one-off image, save it with page.screenshot(). For a visual regression test, use Playwright Test’s expect(page).toHaveScreenshot(), which captures and compares against an expectation after consecutive screenshots match. This assertion is part of Playwright Test and is not interchangeable with simply writing an image file.
const { test, expect } = require('@playwright/test');
test('home page rendering', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveScreenshot('home.png');
});
Use a controlled environment when creating and comparing baselines. Differences in OS, browser version, fonts, hardware, power source, or headless mode can produce pixel differences unrelated to an application change. Review the PageAssertions API for assertion options and baseline behavior.
5. cURL, Python, and Node.js alternatives
Playwright’s browser API is for JavaScript or TypeScript. If your calling application uses Python or another environment, you can still run Playwright in its supported language bindings, or call a screenshot service over HTTP. These examples use ScreenshotNeo’s documented API and return the image response.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
with open("shot.webp", "wb") as f:
f.write(r.content)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = require('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
Replace the placeholder with an API key and review the ScreenshotNeo API documentation for request options and response headers.
Or skip the browser setup
A single request can return a screenshot without installing or managing a local WebKit browser. ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Cookie banners are accepted and removed before capture, along with known newsletter popups and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots. All features are on every plan. See the API docs.
Create a free ScreenshotNeo account for 1,000 screenshots a month, with no card required.
Performance, reliability, and cost
- Performance: Reuse a browser process for multiple captures when running a batch, and close pages and browsers when finished. Full-page, device-scale, and high-resolution captures can increase rendering time, memory use, and output size.
- Reliability: Always close the browser in a
finallyblock so errors do not leave browser processes running. Set navigation and operation timeouts deliberately for slow or unresponsive sites. A successful navigation does not guarantee that client-rendered content is ready; wait for the relevant selector. - Cost: Local Playwright has no per-screenshot API charge, but browser execution consumes machine time, memory, storage, and CI resources. A hosted API has a plan cost; ScreenshotNeo has a free tier and published paid tiers described above. Select based on capture volume and whether you want to manage browser infrastructure.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| WebKit executable missing | The package is installed but its browser binary is not. | Run npx playwright install webkit for the environment executing the script. |
| Browser fails to launch on Linux | Required system libraries are absent. | Install Playwright’s WebKit dependencies with npx playwright install-deps webkit where supported, or use a compatible Playwright environment. |
| Screenshot is blank or incomplete | The page has not rendered its client-side content, or resources are still loading. | Wait for a meaningful locator to become visible and check page errors and network failures. |
| Full-page output omits lazy content | The site loads images or sections only when they approach the viewport. | Scroll through the page and wait for relevant content before capturing; use a site-specific readiness condition. |
| Screenshot differs between runs | Animations, caret, dynamic data, fonts, or environment differences changed pixels. | Disable animations, hide the caret, mask dynamic regions, and keep browser and host configuration fixed. |
| Image is unexpectedly large | Device-pixel scaling, a tall full-page page, or a lossless format increased output size. | Use CSS scale, capture only the needed region, or choose JPEG/WebP when appropriate. |
| Navigation hangs | The selected load condition waits on requests that never become idle, such as analytics or streaming. | Use a more suitable waitUntil condition and wait separately for the content needed in the screenshot. |
FAQ
Does WebKit mean Safari?
Playwright launches its WebKit browser build. It is useful for WebKit coverage, but a screenshot from it is not a guarantee of pixel-identical output to every installed Safari version and operating system.
Can I capture only one element?
Yes. Use a locator’s screenshot method to capture an element. See the Playwright Page API for locator screenshot details.
Can I save a PDF instead?
Playwright’s screenshot method produces an image. For PDF output through ScreenshotNeo, use its capture_pdf MCP tool or consult the API documentation for supported PDF parameters.
Should I use a screenshot file or a visual assertion?
Save a file with page.screenshot() when you need an artifact. Use toHaveScreenshot() when a test should compare rendering against a visual baseline.


