Use await page.evaluate(() => ...) to run JavaScript in the browser page and return a value to your Puppeteer script. The callback runs in the page’s context, not Node.js: pass any Node-side data as arguments rather than trying to reference it from inside the callback.
Run JavaScript in the page context
page.evaluate(pageFunction, ...args) runs the supplied function in the page and returns its result to your script. Prefer a function over a string: Puppeteer’s API documentation says functions are easier to debug and work better with TypeScript. The callback’s result is serialized for transfer back to Node.js.
const title = await page.evaluate(() => document.title);
console.log(title);
The code inside the callback can use browser-page objects such as document. It cannot use variables or helper functions that exist only in the surrounding Node.js script.
Pass Node.js values into the callback
Supply values after the callback. Puppeteer passes them as positional arguments to the function running in the page.
#1 Best Overall
const suffix = ' — checked';
const label = await page.evaluate(
pageSuffix => `${document.title}${pageSuffix}`,
suffix,
);
console.log(label);
Name the callback parameter explicitly; it receives the value, not the Node-side variable’s lexical scope. Define any helper logic the page needs inside the callback, or pass the necessary data as arguments. A JSHandle can also be supplied as an argument when you need to use an object already obtained from the page.
Handle asynchronous page work
Await the Puppeteer call in Node.js. If the page function returns a Promise, Puppeteer waits for it to resolve and returns its resolved value.
const readyState = await page.evaluate(async () => {
await new Promise(resolve => setTimeout(resolve, 100));
return document.readyState;
});
console.log(readyState);
This only waits for the Promise your callback returns. A delay does not guarantee that an application-specific condition has been met. When you need a particular element or state to appear, use an appropriate Puppeteer wait strategy before evaluating it.
Rank #2
Choose the right evaluation method
| Need | Method | What it returns or does |
|---|---|---|
| Read or compute a value in the current page | page.evaluate() |
Returns the serialized result; waits for a returned Promise to resolve. |
| Keep a page object or DOM node for later operations | page.evaluateHandle() |
Returns a JSHandle; a referenced element is represented by an ElementHandle. |
| Run a callback on the first element matching a selector | page.$eval() |
Passes the matched element as the callback’s first argument. Throws if no element matches. |
| Install setup code before page scripts | page.evaluateOnNewDocument() |
Runs after a new document is created and before its scripts execute. |
These methods differ by what they target, when they run, and whether you get a serialized value or a live in-page reference.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesUse evaluateHandle for a reference
A normal evaluation does not give Node.js a live DOM object. For example, returning document.body through evaluate serializes the result rather than transferring a usable browser DOM node. Use a handle when you need to keep and operate on the page object.
const body = await page.evaluateHandle(() => document.body);
const html = await body.evaluate(element => element.innerHTML);
console.log(html);
await body.dispose();
Handles retain references to in-page objects. Dispose of them when you are finished, unless navigation or execution-context destruction has already disposed of them.
Use $eval for one selector match
$eval finds the first matching element and supplies it to your callback:
const text = await page.$eval('h1', element => element.textContent);
console.log(text);
If the selector does not match, $eval throws. If the element may appear later, wait for it or use a suitable locator or wait strategy before reading it.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Use evaluateOnNewDocument for early setup
When code must run before a site’s own scripts, register it before navigating to the page:
Rank #4
await page.evaluateOnNewDocument(() => {
// Runs in the new document before its scripts execute.
});
This setup runs on navigation and also applies to qualifying child-frame attachment or navigation events. It is different from evaluate, which executes against the current document.
Common errors and fixes
- “My Node variable is undefined.” The callback cannot close over Node.js scope. Pass the value as an argument to
evaluate. - “I got an empty-looking object instead of a DOM element.” Evaluation serializes its result. Use
evaluateHandleif you need an in-page reference. - “The result is a Promise or arrives too early.” Await the outer
page.evaluatecall. If the callback returns a Promise, Puppeteer awaits its resolution; separately wait for any page condition your task requires. - “
$evalthrows.” The selector may not match an element yet, or at all. Confirm the selector and wait for the element when it is expected to load later. - “Memory or handle count grows during a long run.” Dispose of handles you no longer need with
dispose(). - “TypeScript accepts code that fails in the page.” Node-side types do not establish which browser globals exist at runtime. Check that the evaluated function uses APIs available in the browser page.
Or skip the browser setup
If your goal is a screenshot rather than custom page-side computation, ScreenshotNeo can capture a URL with one request. For example, using cURL:
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 and consent banners, newsletter popups, and chat widgets are removed before capture; bot checks, blank pages, and failed loads are not billed. An MCP server lets AI agents take screenshots, and the free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for the free plan.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Frequently Asked Questions
Can page.evaluate() return a Promise?
Yes. Puppeteer waits for the returned Promise to resolve and passes its resolved value back to Node.js.
Best Value
Can I return a DOM element with page.evaluate()?
The result is serialized, not transferred as a live Node.js DOM object. Use page.evaluateHandle() when you need the page object by reference.
Which Puppeteer version are these API names based on?
The official API references reviewed on October 3, 2026 list evaluate, $eval, and evaluateHandle at version 25.12.0; JSHandle at 25.9.0; and evaluateOnNewDocument at 25.11.0. The JavaScript execution guide is labeled Next, so check the versioned API for the Puppeteer release you have installed.
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.




