Run browser-side JavaScript in the frame you want by calling await frame.evaluate(callback, ...args). Select the right Puppeteer Frame first; pass Node.js values as arguments, because the callback runs in the browser context and cannot access variables from your Node.js scope.
Run JavaScript in a frame
Use frame.evaluate() for code that should run inside an iframe or the main frame. Puppeteer serializes the callback, evaluates it in that frame’s browser context, waits for a returned promise to resolve, and sends the result back to Node.js if it can be serialized. See the Frame.evaluate() API reference and JavaScript execution guide.
const frame = page.frames().find(candidate => candidate.url().includes('/widget'));
if (!frame) throw new Error('Target frame was not found');
const title = await frame.evaluate(() => document.title);
console.log(title);
The callback executes against the selected frame’s document, not automatically against every frame on the page. For the top-level document, use page.mainFrame(); for child frames, locate the relevant frame through page.frames() or the frame tree.
Pass Node.js values into the frame
Variables in the Node.js module are not in scope inside the serialized browser callback. Pass values as trailing arguments to evaluate() instead.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall#1 Best Overall
const selector = '.status';
const status = await frame.evaluate(
selector => document.querySelector(selector)?.textContent?.trim() ?? null,
selector,
);
console.log(status);
Keep the callback self-contained or pass each needed value explicitly. A helper function declared in Node.js is not available inside the browser callback unless you pass its data and define the logic in the callback itself. The function and argument behavior is documented in the Frame.evaluate() reference and JavaScript execution guide.
Find and wait for the intended frame
Frames can attach, navigate, and detach while a page is running. A URL match is convenient when the frame URL is distinctive, but inspecting the iframe element can be more reliable when several frames have similar URLs.
Rank #2
Select by URL
const frame = page.frames().find(candidate => candidate.url().includes('/checkout'));
if (!frame) throw new Error('Checkout frame not found');
await frame.waitForSelector('[data-ready="true"]');
const result = await frame.evaluate(() => ({
title: document.title,
ready: document.querySelector('[data-ready="true"]') !== null,
}));
console.log(result);
frame.waitForSelector() waits for matching content in that frame, including across navigations; it throws if the required element does not appear. See the Frame.waitForSelector() reference.
Select through the iframe element
To identify a frame by its iframe’s name or id, inspect each candidate’s frame element. The current Frame reference recommends reading those attributes from the element rather than relying on the deprecated frame.name() method.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minutefor (const candidate of page.frames()) {
const frameElement = await candidate.frameElement();
if (!frameElement) continue;
const nameOrId = await frameElement.evaluate(el => el.name || el.id);
if (nameOrId === 'payment-frame') {
const result = await candidate.evaluate(() => document.body.innerText);
console.log(result);
break;
}
}
Use childFrames() and parentFrame() when you need to understand nesting. Evaluating in a parent frame does not automatically execute in its nested child frames. Frame navigation and frame-element methods are covered in the Frame class reference.
Choose the right frame API
| Method | Best for | What comes back | Waiting behavior |
|---|---|---|---|
frame.evaluate(fn, ...args) |
Arbitrary JavaScript in a frame | A serialized result | Awaits a returned promise; wait for dynamic elements separately |
frame.evaluateHandle(fn, ...args) |
Keeping a reference to a DOM node or other browser object | A handle to a browser object | Does not replace an explicit content wait |
frame.$eval(selector, fn, ...args) / frame.$$eval(selector, fn, ...args) |
Running a function on the first matching element or on matching elements | The function’s serialized result | Targets matching elements; use an explicit wait if content is dynamic |
frame.waitForSelector(selector, options) |
Waiting for matching frame content | An element handle, or null for the documented hidden case |
Waits for the selector; throws if required content does not appear |
frame.locator(selector) |
Interactions such as clicking or filling | A locator for the target | Automatically waits for presence and state as needed |
Use evaluate() when the task calls for custom browser-side JavaScript. For direct interaction, a locator is generally preferable because it handles waiting and state checks. The Page interactions guide explains locators, and the Frame.$eval() reference documents element-focused evaluation.
Rank #4
Return data or keep a live browser object
Ordinary evaluate() returns values that Puppeteer can serialize, such as strings, numbers, arrays, and plain objects. A DOM node returned this way is not a usable live node in Node.js. Use evaluateHandle() when you need to retain a reference to the browser object.
const bodyHandle = await frame.evaluateHandle(() => document.body);
try {
const text = await bodyHandle.evaluate(body => body.innerText);
console.log(text);
} finally {
await bodyHandle.dispose();
}
Handles are disposed when their associated frame navigates away or their parent context is destroyed. Dispose of handles when finished to release them promptly. See the JavaScript execution guide and Frame class reference.
Best Value
- Used Book in Good Condition
Troubleshoot frame evaluation
- The callback says a Node variable is undefined: pass it as an argument, for example
frame.evaluate(value => document.title + value, value). The callback runs in the browser context. - The result is an empty object or is not a DOM node: return serializable data for ordinary
evaluate(); useevaluateHandle()for a live browser-object reference. - A selector is missing: confirm you selected the correct frame, then wait with
frame.waitForSelector(selector). If it never appears, the wait can time out. For clicks and fills, consider a locator. - The script reads the wrong page: inspect
frame.url()or the candidate’s iframename/id; the top-level page’s DOM does not contain a child frame’s document. - The content is in a nested iframe: find that nested frame in the frame tree and call
evaluate()on it directly. - A saved handle stops working after navigation: navigation or context destruction disposes associated handles. Acquire a new handle after navigation and dispose of old ones when finished.
Or skip the browser setup
If the goal is to capture a page rather than run custom JavaScript in its frame, ScreenshotNeo provides a screenshot API and MCP server. This one-call example returns a screenshot file; see the API documentation for options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo can accept cookie or consent banners and remove known consent platforms, newsletter popups, and chat widgets before capture. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Its MCP server lets AI agents use screenshot and PDF tools. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000.
Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month without a card.
Frequently Asked Questions
Can I run JavaScript in a Puppeteer iframe?
Yes. Find the iframe’s Puppeteer Frame and call frame.evaluate(); the callback runs in that frame’s browser context.
Free tools Windows power users keep installed
One-click scans. No signup required.
Does frame.evaluate() wait for a returned promise?
Yes. Puppeteer waits for the callback’s returned promise to resolve and returns its value, if serializable.
Which Puppeteer version is required?
The cited API references are labeled Puppeteer 25.10.0 through 25.12.0, but they do not establish a minimum version. Check the API reference for your installed version.
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.




