Recommended Free Tools
Click the button, wait for the specific result you want to show, then call page.screenshot(). A click waits for Playwright’s actionability checks; it does not automatically wait for your app’s asynchronous update, navigation, or popup.
Capture a screenshot after an in-page change
Use a locator that identifies the button by its accessible role and name, then assert that the resulting UI is visible before capturing it. Replace the example names with ones that match your application:
As an Amazon Associate I earn from qualifying purchases.
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByText('Saved')).toBeVisible();
await page.screenshot({ path: 'after-click.png' });
This is suitable for an existing Playwright test with page and expect available. The assertion is not just a pause: it connects the capture to the state the image should represent. Playwright describes locators as the central piece of its auto-waiting and retry-ability (locator guide).
Choose the wait that matches the button’s result
The page updates in place
Assert the visible content that proves the change completed. For example, after opening a details panel:
#1 Best Overall
await page.getByRole('button', { name: 'Show details' }).click();
await expect(page.getByRole('region', { name: 'Details' })).toBeVisible();
await page.screenshot({ path: 'details.png' });
Use a meaningful, user-facing locator for the expected result rather than a fixed timeout. The exact locator depends on the app’s accessible names and rendered content.
The click navigates
Wait for the known destination with waitForURL(), then assert that the destination has rendered the content relevant to the screenshot:
Rank #2
await page.getByRole('button', { name: 'Continue' }).click();
await page.waitForURL('**/next-step');
await expect(page.getByRole('heading', { name: 'Next step' })).toBeVisible();
await page.screenshot({ path: 'next-step.png' });
Playwright marks waitForNavigation() deprecated and describes it as inherently racy; use waitForURL() when you know the destination (Page API).
The click opens a popup or new tab
Register the popup wait before clicking so the event cannot be missed. The popup is a Page, so you can assert its content and capture it:
const popupPromise = page.waitForEvent('popup');
await page.getByRole('button', { name: 'Open report' }).click();
const popup = await popupPromise;
await expect(popup.getByRole('heading', { name: 'Report' })).toBeVisible();
await popup.screenshot({ path: 'report.png' });
See Playwright’s Pages guide for popup behavior.
The click starts a download
If you need to observe the download, register the event before clicking:
const downloadPromise = page.waitForEvent('download');
await page.getByRole('button', { name: 'Download report' }).click();
const download = await downloadPromise;
await page.screenshot({ path: 'page-after-download-start.png' });
Decide whether the screenshot should show the page before or after the download starts; a downloaded file itself is not a page screenshot. The event ordering follows the Page API’s download example.
Rank #4
Choose what to capture and where the image goes
| Need | Playwright approach | Result |
|---|---|---|
| Current viewport | await page.screenshot({ path: 'viewport.png' }); |
Saves the visible viewport. |
| Full scrollable page | await page.screenshot({ path: 'full-page.png', fullPage: true }); |
Saves a full-page capture. |
| One element | await page.getByRole('main').screenshot({ path: 'main.png' }); |
Saves the selected locator’s screenshot. |
| Image bytes for downstream processing | const imageBytes = await page.screenshot(); |
Returns image bytes instead of saving via a path. |
These capture options are documented in the Page API. Use a page screenshot when the whole page state matters and a locator screenshot when only a specific element is relevant.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsUse screenshot assertions for visual regression tests
If the goal is to detect visual changes rather than produce a one-off image, use Playwright Test’s expect(page).toHaveScreenshot() to create or compare a screenshot baseline (visual comparisons guide).
Keep capture and comparison environments consistent. Operating system, browser version, settings, hardware, power source, and headless mode can affect rendering, so a mismatch does not necessarily mean the application changed.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Troubleshoot a screenshot that looks wrong
- The screenshot shows the old state: the click completed, but the application update did not. Add a web-first assertion for the confirmation, updated heading, or other visible state that the screenshot is intended to document.
- The destination page is missing: wait for the expected URL and assert destination content before capturing. Prefer
waitForURL()over deprecatedwaitForNavigation(). - The popup is not captured: start
page.waitForEvent('popup')before the click, then take the screenshot from the returned popup Page. - The click targets the wrong button or is ambiguous: use a user-facing locator such as
getByRole('button', { name: 'Save' }). Long CSS or XPath chains are more closely tied to implementation details and can break when the DOM changes. - A visual comparison fails across machines: compare in a consistent rendering environment, including browser and operating-system conditions, before treating the difference as an application regression.
Or skip the browser setup
For a one-request screenshot service, ScreenshotNeo accepts a URL and returns a screenshot or PDF. This is not a replacement for clicking through an application interaction in Playwright: use it when a URL capture is what you need.
Example cURL call, with the target URL adapted to the page you want to capture:
Free tools Windows power users keep installed
One-click scans. No signup required.
Quick Recap
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before capture; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for free.
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.




