How to Get the Message from a Puppeteer Dialog
Use Puppeteer’s `dialog` event and `dialog.message()` to read an alert, confirm, prompt, or beforeunload message before handling it.
Register a dialog event handler on the Puppeteer Page, then call dialog.message() on the supplied Dialog object. It returns the displayed dialog message as a string. Read it before accepting or dismissing the dialog so the page can continue. Puppeteer dispatches Dialog instances through the Page’s dialog event. Puppeteer Dialog API · Dialog.message() reference
1. Read the message in a dialog handler
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
page.on('dialog', async dialog => {
console.log('Type:', dialog.type());
console.log('Message:', dialog.message());
await dialog.dismiss();
});
await page.goto('https://example.com');
await page.evaluate(() => alert('Deployment complete'));
} finally {
await browser.close();
}
Install Puppeteer with npm install puppeteer and run this as an ES module in Node.js. The handler receives the Dialog instance, synchronously reads its message, then asynchronously dismisses it. The core is just page.on('dialog', handler) and dialog.message(). Puppeteer’s official example follows this pattern. Dialog class example
2. Choose how to handle the dialog
Reading the message does not resolve a native browser dialog. The handler should call accept() or dismiss() according to the test or automation’s intended behavior. These methods return promises, so await them.
| Dialog type | What to read | Typical handling |
|---|---|---|
alert |
dialog.message() |
Usually dismiss or accept; either closes it. |
confirm |
dialog.message() |
Accept for OK; dismiss for Cancel. |
prompt |
Message with dialog.message(); initial input with dialog.defaultValue() |
Call accept('text') to submit text, or dismiss to cancel. |
beforeunload |
dialog.message() |
Accept or dismiss based on whether the navigation should proceed. |
The documented types are alert, beforeunload, confirm, and prompt. defaultValue() is separate from the message: it returns the prompt’s default input, and an empty string when the dialog is not a prompt. Puppeteer defaultValue() reference · accept() reference
Capture and assert a message
For tests, save the value in the event handler and assert it after triggering the dialog. Install the listener before the action that may open the dialog; otherwise the action can pause waiting for a dialog your code has not handled.
const seenMessages = [];
page.on('dialog', async dialog => {
seenMessages.push({ type: dialog.type(), message: dialog.message() });
await dialog.accept();
});
await page.evaluate(() => confirm('Delete this record?'));
if (seenMessages[0]?.message !== 'Delete this record?') {
throw new Error(`Unexpected dialog: ${JSON.stringify(seenMessages)}`);
}
Choose accept or dismiss deliberately in a confirm dialog: accepting makes the page’s confirm() call return true, while dismissing makes it return false. For a prompt, pass the intended input to accept(promptText); omitting it accepts with the dialog’s normal default behavior.
3. Do not confuse the message with prompt input
dialog.message() returns the text displayed in the dialog. dialog.defaultValue() returns a prompt’s initial input value, not its message. The message is available through Puppeteer’s Dialog object in the Page event handler; it is not ordinary page DOM text. message() returns a string
4. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| The click, navigation, or evaluation hangs. | A JavaScript dialog opened and no handler resolved it. | Register page.on('dialog', ...) before the triggering action, then await accept() or dismiss(). |
| No message was captured. | The listener was added after the dialog trigger, or the site displayed an HTML modal rather than a native JavaScript dialog. | Attach the listener first. For an HTML modal, inspect and query its DOM instead; it does not emit the native Page dialog event. |
defaultValue() is empty. |
The dialog is not a prompt, or its prompt default is empty. | Use message() for displayed text; use defaultValue() only when you need prompt input. |
| The prompt received unexpected text. | accept() was called without the intended input. |
Call await dialog.accept('your input') for a prompt. |
| The handler seems to run more than once. | The page opened multiple dialogs during the flow. | Record each event, including dialog.type(), and handle every dialog that the workflow can produce. |
| The process exits before cleanup. | Browser cleanup was not protected against errors. | Put automation in try/finally and close the browser in the finally block. |
5. Reliability, performance, and cost
message() is a synchronous read of the Dialog object, so there is no separate request or wait needed to fetch the string. The important reliability step is resolving each dialog: an unhandled native dialog can block page actions that depend on the browser continuing. Attach the listener before the interaction and await its accept or dismiss operation.
For a local Puppeteer run, the dialog read itself adds no service charge; runtime and browser setup are the practical costs. Keep handlers focused, record only the message data needed for debugging, and avoid leaving a dialog unresolved. Puppeteer versions can differ in API typings and behavior, so check the documentation for the version installed in your project.
6. Or skip the browser setup
If your task is to capture a page rather than inspect a JavaScript dialog, ScreenshotNeo provides a website screenshot API and MCP server. It cannot return a Puppeteer Dialog object or replace dialog assertions, but it can avoid browser setup for screenshot work.
cURL:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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}`);
See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot. 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; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month.
7. FAQ
Does dialog.message() return a promise?
No. It returns a string synchronously. The accept and dismiss methods are asynchronous.
Can I read an HTML popup with this event?
No. The Page dialog event is for JavaScript browser dialogs. An HTML popup is part of the page and must be inspected through the DOM.
Should I accept or dismiss after reading?
Use whichever response matches the behavior you need to test. Always resolve the dialog so the browser can proceed.


