Playwright is an open-source browser automation library from Microsoft that controls Chromium, Firefox and WebKit through one API, used to test web apps, take screenshots and PDFs, and script any task a person could do in a browser.
Microsoft released it in January 2020. Several of its first engineers had built Puppeteer at Google, and Playwright kept a similar style while adding cross-browser support. It has official libraries for JavaScript and TypeScript, Python, Java and .NET. This entry is part of the screenshot and rendering glossary.
A plain explanation
Playwright starts a browser, opens pages and acts on them: go to a URL, click, type, wait for an element, read text, take a screenshot. Two ideas set it apart.
- Browser contexts. A context is a fresh, isolated browser profile with its own cookies, storage, viewport, locale and device pixel ratio. Many contexts share one browser process, so you get isolation without the cost of a new launch.
- Locators with auto-waiting.
page.getByRole('button', { name: 'Save' }).click()waits until the button exists, is visible, stable and enabled. Most flaky "element not found" bugs from older tools disappear.
How it works technically
Playwright does not drive the Firefox or Safari you have installed. It downloads its own builds, matched to the library version, because it relies on protocol hooks that it adds to Firefox and WebKit. For Chromium it uses the Chrome DevTools Protocol, and it can also drive branded Chrome or Edge through channel.
Those builds take disk space. After npx playwright install for Playwright 1.64.1 on an Apple silicon Mac, we measured the cache folder:
| Download | Version | Size on disk |
|---|---|---|
| Chromium (Chrome for Testing) | 156.0.8078.4 | 366 MB |
| Chromium headless shell | 156.0.8078.4 | 204 MB |
| WebKit | 27.2 | 299 MB |
| Firefox | 157.0 | 294 MB |
| FFmpeg (video recording) | - | 2.9 MB |
That is about 1.2 GB for the default set. Install only what you use, for example npx playwright install chromium, and include the size in your Docker image budget.
How to take a screenshot in Playwright, Puppeteer and RenderScreenshot
Playwright. Settings live on the context, the wait is a locator, and animations: 'disabled' stops CSS animations before the capture.
import { chromium } from 'playwright'; const url = process.argv[2] ?? 'https://example.com'; const browser = await chromium.launch(); try { const context = await browser.newContext({ viewport: { width: 1280, height: 800 }, deviceScaleFactor: 2, colorScheme: 'light', locale: 'en-US', }); const page = await context.newPage(); await page.goto(url); await page.locator('body').first().waitFor({ state: 'visible' }); await page.screenshot({ path: 'playwright.png', fullPage: true, animations: 'disabled' }); console.log('saved playwright.png from', browser.browserType().name(), browser.version()); } finally { await browser.close(); }
Puppeteer, for comparison. The same capture uses page-level calls: the viewport and media features are set on the page, not on a context.
import puppeteer from 'puppeteer'; const url = process.argv[2] ?? 'https://example.com'; const browser = await puppeteer.launch(); try { const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 800, deviceScaleFactor: 2 }); await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'light' }]); await page.goto(url, { waitUntil: 'load' }); await page.waitForSelector('body', { visible: true }); await page.screenshot({ path: 'puppeteer.png', fullPage: true }); console.log('saved puppeteer.png from', await browser.version()); } finally { await browser.close(); }
RenderScreenshot. The same options as one request, with no browser to install. dark_mode=false forces the light scheme, as colorScheme: 'light' does above.
curl --get https://api.renderscreenshot.com/v1/screenshot \ -H "Authorization: Bearer $RS_API_KEY" \ --data-urlencode 'url=https://example.com' \ -d width=1280 -d height=800 -d scale=2 \ -d full_page=true -d dark_mode=false -d locale=en-US \ --output page.png
Tested on 2026-10-15 with Node 22.18, Playwright 1.64.1 (Chromium 156.0.8078.4) and Puppeteer 24.43.1 (run in headless shell mode, Chrome 148). The curl request follows the GET endpoint docs and was not run for this page.
Common mistakes
deviceScaleFactoron the page. In Playwright it is a context option.page.setViewportSize()changes only width and height.- Expecting WebP.
page.screenshotwrites PNG or JPEG. Convert afterwards if you need WebP. - Skipping the browser install in CI. The npm package does not include browsers. Run
npx playwright install --with-deps chromiumin the image, or the first launch fails with "Executable doesn't exist". - Sleeping instead of waiting.
page.waitForTimeoutexists, but a locator wait orwaitForFunctionis faster and less flaky.
Related terms
- Puppeteer: Google's Chrome-first library that Playwright grew from.
- Headless browser: what Playwright launches by default, with timings for each engine.
- Headless Chrome: why Playwright's default Chromium is the headless shell.
- Model Context Protocol: how Playwright is exposed to AI agents through Playwright MCP.
The full tutorial is taking screenshots with Playwright, and the trade-offs are in Puppeteer vs Playwright for screenshots. To capture without running browsers, create a free account.