Call await page.exposeFunction('name', callback) in your Puppeteer script. Puppeteer installs that function on the page’s window; when page JavaScript calls it, the callback runs in Node.js and its result is returned as a Promise. Await the page-side call if you need its result.
Expose a Node.js callback to the page
This runnable example exposes a Node.js function that calculates an MD5 hash, then calls it from the browser page using page.evaluate():
As an Amazon Associate I earn from qualifying purchases.
import puppeteer from 'puppeteer';
import crypto from 'node:crypto';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex'),
);
const hash = await page.evaluate(async () => {
return await window.md5('PUPPETEER');
});
console.log(hash);
} finally {
await browser.close();
}
Register the bridge before any page code tries to call it. The callback can be asynchronous: Puppeteer waits for a returned Promise and passes its resolved value back to the page. The API reference for Page.exposeFunction() documents this behavior and notes that exposed functions survive navigations.
TypeScript window typing
TypeScript projects may need a declaration for the added property, with argument and return types that match the callback. There is no single declaration pattern for every project; place the declaration where your project’s TypeScript configuration makes it available to the page-evaluation code.
#1 Best Overall
Choose the right Puppeteer execution API
| Need | API | Where code runs | Key distinction |
|---|---|---|---|
| Page JavaScript must request Node.js work | page.exposeFunction() |
The callback runs in Node.js; the named function is installed on page window. |
Calls return a Promise; the exposed function survives navigation. |
| Run a calculation or inspect state in the page | page.evaluate() |
Browser page context | It cannot close over Node.js variables; pass required data as arguments. |
| Set up page-side behavior before the site’s scripts | page.evaluateOnNewDocument() |
Browser page context, before page scripts | Runs on navigation and when child frames attach or navigate; it is not a Node.js callback bridge. |
Puppeteer’s JavaScript execution guide explains that page.evaluate() serializes and runs the supplied function in the page. It does not bring the function’s Node.js lexical scope with it, so pass data explicitly. A Promise returned by the evaluation is automatically awaited. Returned values are serialized; use page.evaluateHandle() if you need to retain an in-page object such as a DOM node by reference.
Use page.evaluateOnNewDocument() for a page-context preload that must run before site scripts. Use page.waitForFunction() when you need to wait for a page-context predicate to become truthy; it supports arguments and asynchronous page functions.
Rank #2
Pass data and handle results safely
- Choose a narrow name and contract. Pick a specific name that is unlikely to collide with a site global, and make clear what arguments the page may pass.
- Validate at the Node.js boundary. Page inputs should be treated as untrusted. Check types, lengths, and allowed values before performing work.
- Await when the result matters. Since calls return a Promise, page code can
await window.name(input). Catch rejections in page code or handle them in the surrounding Puppeteer flow according to your application’s needs. - Remove the bridge when finished. Call
await page.removeExposedFunction('name')to remove a previously exposed function from the page’swindow.
Security and page-context boundaries
An exposed function is a capability available to JavaScript that can access its name in the page. Keep callbacks narrow: do not expose general filesystem, shell, credential, or arbitrary network access to page code. Validate every argument and grant only the specific operation the page requires.
Recommended Free Tools
For related tabs and popups, remember that Puppeteer’s BrowserContext represents an isolated user context, and a popup opened by a page belongs to that page’s context. Consider which pages can reach the exposed capability when designing your flow.
Rank #3
Troubleshooting
window.nameis undefined: Ensurepage.exposeFunction()completed before the page calls it. Use the exact same name on both sides and confirm you are evaluating in the page associated with that exposure.- The call never seems to finish: If the callback returns a Promise, it must settle. Check for unresolved work in the Node.js callback and ensure page code awaits the call only when appropriate.
- Node.js variables are undefined inside
page.evaluate(): The evaluated function runs in the browser, not in Node.js. Pass values as arguments, or expose a narrowly scoped callback if the page needs Node.js work. - The page receives an unexpected result: Values crossing the evaluation boundary are serialized. For object references that must remain usable in the page, consider
page.evaluateHandle()rather than returning the object frompage.evaluate(). - A call fails after navigation: Exposed functions are documented to survive navigations. Check that the call uses the same Puppeteer page and exposed name, and inspect whether application page code or navigation timing is preventing the call.
Or skip the browser setup
If your goal is a screenshot rather than custom Node.js work in a browser page, ScreenshotNeo returns a screenshot or PDF with one GET request. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000. 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
Sign up for 1,000 free screenshots a month, with no card required.
Quick Recap
Rank #4
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.




