How to Take a Screenshot of a Page with a Browser Alert in Playwright
Handle JavaScript alerts before capturing a Playwright page. Learn how to save the message in the screenshot, choose accept or dismiss, and troubleshoot blocked actions.
Handle the browser alert before taking a Playwright screenshot. Register a dialog handler before the action that triggers it, collect the message if you need it, then accept or dismiss the dialog. A page screenshot captures page content; do not assume it includes the browser’s native alert chrome. To show the alert text in the image, render the collected message into the page before capturing.
This guide uses Playwright’s JavaScript API. The pattern applies to JavaScript dialogs such as alert, confirm, prompt, and beforeunload. See the official Playwright dialogs guide and Page API.
Handle the alert, then take the screenshot
Install the handler before clicking the control that opens the alert. The handler below saves the dialog message and accepts the alert so the click and later page actions can continue.
const alertMessagePromise = new Promise(resolve => {
page.once('dialog', async dialog => {
const message = dialog.message();
await dialog.accept();
resolve(message);
});
});
await page.getByRole('button', { name: 'Show alert' }).click();
const alertMessage = await alertMessagePromise;
await page.screenshot({ path: 'page.png', fullPage: true });
This captures the page after the dialog is accepted. If the alert’s message itself needs to appear in the image, insert it into the page first.
await page.evaluate(text => {
const note = document.createElement('pre');
note.id = 'captured-alert';
note.textContent = `Alert: ${text}`;
document.body.append(note);
}, alertMessage);
await page.screenshot({ path: 'page-with-alert-message.png', fullPage: true });
Rendering the message into the page is a practical workaround based on the dialog and screenshot APIs. Playwright’s documentation treats dialog handling and page screenshots as separate operations; it does not promise that a page screenshot contains native browser alert chrome.
Complete runnable example
This Node.js script starts a local page that opens an alert, handles it, writes the message into the document, and saves a full-page screenshot. Install Playwright with npm install playwright and install its browser with npx playwright install chromium, then save this as alert-screenshot.js and run node alert-screenshot.js.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.setContent(`
<!doctype html>
<html>
<body>
<h1>Alert example</h1>
<button onclick="alert('Saved successfully')">Show alert</button>
</body>
</html>
`);
const alertMessagePromise = new Promise(resolve => {
page.once('dialog', async dialog => {
const message = dialog.message();
await dialog.accept();
resolve(message);
});
});
await page.getByRole('button', { name: 'Show alert' }).click();
const alertMessage = await alertMessagePromise;
await page.evaluate(text => {
const note = document.createElement('pre');
note.id = 'captured-alert';
note.textContent = `Alert: ${text}`;
document.body.append(note);
}, alertMessage);
await page.screenshot({ path: 'page-with-alert-message.png', fullPage: true });
await browser.close();
})().catch(error => {
console.error(error);
process.exitCode = 1;
});
To capture only the page after the alert is handled, omit the page.evaluate block and save to a filename such as page.png.
Choose accept, dismiss, or a response
| Dialog | Typical handling | Effect to consider |
|---|---|---|
alert |
await dialog.accept() or await dialog.dismiss() |
The page continues after the alert is handled. |
confirm |
Accept to choose OK; dismiss to choose Cancel. | The application may take a different path for each choice. |
prompt |
await dialog.accept('your response'), or dismiss. |
Pass the text the scenario should submit; dismiss to cancel. |
beforeunload |
Accept or dismiss according to the navigation scenario. | The choice can determine whether navigation proceeds. |
Use the outcome the test or capture scenario is meant to represent. Accepting a confirmation when the intended behavior is Cancel can change the resulting page, so dialog handling is part of the scenario rather than just screenshot setup.
Accept a prompt with text
page.once('dialog', async dialog => {
console.log('Prompt text:', dialog.message());
await dialog.accept('Example response');
});
await page.getByRole('button', { name: 'Ask a question' }).click();
Dismiss a dialog
page.once('dialog', async dialog => {
console.log('Dismissing:', dialog.message());
await dialog.dismiss();
});
await page.getByRole('button', { name: 'Confirm action' }).click();
Use a page-level or context-level listener
A page listener is suitable when one page or one test step needs a particular response. A context listener can apply a shared policy to pages in the same browser context. In either case, settle every dialog by accepting or dismissing it.
context.on('dialog', async dialog => {
console.log(dialog.type(), dialog.message());
await dialog.accept();
});
Without a page or browser-context dialog listener, Playwright automatically dismisses dialogs. Once a listener is installed, it must handle the dialog: a handler that only logs the message can leave the triggering action stalled. See the BrowserContext API.
Screenshot options after handling the dialog
Dialog handling and screenshot configuration are separate. After settling the dialog, use page.screenshot() options to shape the image:
pathsaves the image to a file, for examplepage.png.fullPage: truecaptures the full scrollable page rather than only the viewport.typeselects an image format supported by the API, such as PNG or JPEG; the default is inferred from the file extension when a path is supplied.cliplimits capture to a specified page rectangle.maskcan cover selected page locators in the screenshot.scalecontrols whether output follows CSS pixels or device pixels.
Check the current Page screenshot API for the complete option set and types supported by your installed Playwright version. These options do not make the native alert part of the webpage image.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. A single GET request returns an image or PDF. It captures website pages; it does not automate a Playwright dialog or promise to include native alert chrome. If you need a routine website screenshot after deciding what the alert scenario should do, this can avoid managing a browser yourself. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
- Cookie banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. Response headers report the page verdict and billing status.
- An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
- The Free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.
Sign up free for 1,000 screenshots a month, no card required.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| The click or next page action hangs. | A dialog listener was installed but did not accept or dismiss the dialog, or no handler was ready when the dialog opened. | Register the handler before the triggering action and call accept() or dismiss() inside it. |
| The alert text is missing from the screenshot. | A page screenshot captures page content; the native browser dialog is separate. | Read dialog.message(), handle the dialog, then render the message into the page or save it in another test artifact. |
| The dialog disappears without the expected choice. | No page or context listener was registered, so Playwright automatically dismissed it. | Install an explicit listener before the action and accept or dismiss according to the intended scenario. |
| The wrong result appears after a confirm or prompt. | The handler selected the wrong branch or did not supply the expected prompt text. | Use accept() for OK and dismiss() for Cancel; pass the desired string to accept(text) for a prompt. |
| The screenshot omits lower page content. | The default capture covers the viewport only. | Set fullPage: true, or use clip when only a specific region is required. |
| The message insertion fails or appears as markup. | Interpolating untrusted content into HTML can alter the document. | Use textContent, as in the example, rather than building an HTML string from the message. |
Performance, reliability, and cost
For a single capture, the main reliability concern is sequencing: install the handler before the action, settle the dialog, then screenshot. Await each step so the screenshot cannot race ahead of dialog handling or message rendering. Use a one-time page.once listener for a known single dialog; use page.on or a context listener only when repeated dialogs are expected, and ensure each event is handled.
A local Playwright run has no per-screenshot API charge, but it does require a compatible browser installation and the compute and maintenance needed to run it. ScreenshotNeo pricing is $0 for 1,000 monthly shots, then $5 for 3,000 (Starter), $15 for 15,000 (Growth), $39 for 60,000 (Pro), $99 for 250,000 (Scale), or $249 for 1,000,000 (Business). Yearly billing gives two months free. Only clean shots are billed, and the response identifies the verdict and billing status. Choose based on the number of successful page captures you need and the operational cost of running your own browser.
For debugging a sequence of interactions, Playwright tracing can record screenshots and action snapshots for review in Trace Viewer. See the official Trace Viewer documentation. A trace is useful for understanding what happened around a dialog; it does not change the need to handle a blocking dialog in the scenario.
FAQ
Can Playwright screenshot the native alert window?
Do not rely on that. The documented page screenshot API captures the page, and the documentation reviewed does not promise native alert chrome in the image. Render the message into page content if it must be visible.
Does Playwright dismiss alerts automatically?
Yes, when no page or browser-context dialog listener is registered. With a listener, your handler must accept or dismiss the dialog.
Should I accept or dismiss the alert?
Choose the result the test is meant to represent. For a simple alert either settles it; for confirm, prompt, and beforeunload dialogs the choice can affect page behavior.
Can I still use full-page screenshots?
Yes. Handle the dialog first, then call page.screenshot({ fullPage: true }) to capture the full scrollable page.


