To listen for iframe changes in Puppeteer, register frameattached, framenavigated, and framedetached listeners on the parent Page. Each callback receives the affected Frame, which you can inspect to identify its URL and position in the frame tree.
How do I listen for frame changes in Puppeteer?
Register listeners on the Page before the action or navigation that may change the frame tree. The Page emits lifecycle events for child frames as well as the main frame.
As an Amazon Associate I earn from qualifying purchases.
page.on('frameattached', frame => {
console.log('Frame attached:', frame.url());
});
page.on('framenavigated', frame => {
console.log('Frame navigated:', frame.url());
});
page.on('framedetached', frame => {
console.log('Frame detached:', frame.url());
});
This is an idiomatic pattern using Puppeteer’s documented event names and Frame callback values. [PageEvent reference]
What each frame event means
| Event | When it fires | Callback value |
|---|---|---|
frameattached |
A frame is attached to the page. | The affected Frame |
framenavigated |
A frame navigates to a new URL. | The affected Frame |
framedetached |
A frame is detached from the page. | The affected Frame |
These are distinct transitions: navigation concerns a frame’s URL transition, while attachment and detachment concern its presence in the page’s frame tree. Puppeteer documents all three as events dispatched on the parent page. [Frame class] [PageEvent reference]
#1 Best Overall
Inspect the frame in a handler
The event payload is a Frame, so a handler can read its URL, inspect its parent, and enumerate its child frames.
page.on('framenavigated', frame => {
const parent = frame.parentFrame();
const children = frame.childFrames();
console.log({
url: frame.url(),
parentUrl: parent?.url() ?? null,
childFrameUrls: children.map(child => child.url()),
});
});
The main frame has no parent, which is why the example uses optional chaining. Frame APIs are documented in Puppeteer’s Frame class reference.
Choose between events, waiting, and a snapshot
- Listen for an ongoing stream: use the lifecycle event listeners when you need to react to every attachment, navigation, or detachment.
- Wait for one matching frame: use
page.waitForFrame(urlOrPredicate, options)when execution should continue after a particular frame appears. - Inspect frames already present: use
page.frames()to get the currently attached frame set. It is a snapshot, not a subscription to future changes.
The Page API documents waitForFrame() and frames(). Register event handlers ahead of the change if you need to observe it rather than inspect the resulting state. [Page class reference]
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteHandle frame navigation without a race
Puppeteer treats History API URL changes as navigation for Frame.waitForNavigation(). That does not make navigation equivalent to attachment: use framenavigated for the ongoing event stream and a navigation wait when a specific action is expected to navigate a frame.
Rank #3
When an action triggers navigation, start the action and wait together so the navigation is not missed:
const [response] = await Promise.all([
page.waitForNavigation(),
page.click('a'),
]);
This is Puppeteer’s documented pattern for page navigation. If the action navigates a child frame, wait on the relevant Frame instead of the page. [Frame class reference] [Page interactions guide]
Run code in newly created frame documents
page.evaluateOnNewDocument() serves a different purpose from Node.js lifecycle listeners. Puppeteer runs the supplied function after a document is created but before its scripts run, including when a child frame attaches or navigates. Use it when you need instrumentation inside each new document context; use Page events when your Node.js code needs to react to frame lifecycle changes.
See the evaluateOnNewDocument() reference.
Troubleshoot missed or confusing frame changes
- A change was not reported: attach the listeners before the triggering action. A later
page.frames()call can show the current set, but cannot replay a past event. - You are listening on the wrong object: register these lifecycle handlers on the parent
Page; the documented events are dispatched there. - You expected an attachment event for a URL change: use
framenavigatedfor a navigation. A frame can navigate without being newly attached. - A click-triggered navigation is intermittently missed: start the navigation wait and click together with
Promise.all, rather than awaiting the click first. - You need to instrument a frame before its page scripts execute: lifecycle callbacks are notifications to Node.js; use
evaluateOnNewDocument()for code that must run in newly created documents.
Version scope
The cited Frame and Page class references are for Puppeteer 25.12.0, and the evaluateOnNewDocument() reference is labeled 25.11.0. The PageEvent reference is labeled “Next”; check the documentation corresponding to your installed Puppeteer version when relying on a version-specific event surface.
Or skip the browser setup
If your goal is to capture a page rather than monitor its frame lifecycle, ScreenshotNeo offers a one-request screenshot API. 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
- 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, and response headers identify the page verdict and billing status.
- An MCP server gives AI agents tools for taking screenshots, getting page information, and capturing PDFs.
- The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Learn about ScreenshotNeo, or sign up free for 1,000 screenshots a month with no card.
Frequently Asked Questions
Does frameattached fire when a frame changes its URL?
No. Use framenavigated for a frame URL transition; attachment and navigation are separate lifecycle events.
Recommended Free Tools
Can I use page.frames() to listen for future iframes?
No. It returns the frames currently attached. Subscribe to Page lifecycle events to observe future changes.
Quick Recap
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.




