What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Pass the object as an argument to page.evaluate(), then assign that argument to window inside the browser context:
const data = {
userId: 123,
featureFlags: { newHeader: true }
};
await page.evaluate((data) => {
window.myData = data;
}, data);
This is the safest general pattern for ordinary JavaScript data. Puppeteer serializes the argument across the Node.js–browser boundary; the callback executes in the page, where window.myData becomes available to the current document.
What crosses the Puppeteer boundary
Your Puppeteer script runs in Node.js, while the function supplied to page.evaluate() runs in the page. A variable in the Node.js closure is not automatically visible in that page function. Pass values explicitly as arguments.
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 minuteBasic injection
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
const data = {
userId: 123,
featureFlags: { newHeader: true },
locale: 'en-US'
};
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.evaluate((value) => {
window.myData = value;
}, data);
const received = await page.evaluate(() => window.myData);
console.log(received);
await browser.close();
The second evaluation is optional; it simply demonstrates that the page can read the global. Objects, arrays, strings, numbers, booleans and null are suitable when they can be serialized by Puppeteer.
#1 Best Overall
Use a stable property name
Choose a name that is unlikely to collide with the site. A namespaced property such as window.__MY_APP_CONFIG__ is easier to identify than a generic name like window.data. If the site already defines the property, decide whether replacement is intentional:
await page.evaluate((value) => {
Object.defineProperty(window, '__MY_APP_CONFIG__', {
value,
writable: false,
configurable: true,
enumerable: false
});
}, data);
Use a normal assignment when page code must update the value. A non-writable property prevents accidental reassignment, but it does not make nested objects immutable.
Inject before site scripts run
page.evaluate() runs only when you call it. If the page’s startup code reads the value during document initialization, it is too late to set it after navigation. Register page.evaluateOnNewDocument() before navigating:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →const data = { theme: 'dark', experiment: 'checkout-v2' };
await page.evaluateOnNewDocument((value) => {
window.__MY_APP_CONFIG__ = value;
}, data);
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
The callback runs after a document is created and before that document’s scripts execute. Puppeteer also invokes it again for later navigations and for newly attached or navigated child frames. That repeated execution affects your design.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
Make repeated execution safe
An assignment is normally idempotent, but initialization with side effects is not. Avoid incrementing counters, appending duplicate DOM nodes or registering the same event listener every time the hook runs. For a one-time setup in each document:
await page.evaluateOnNewDocument((value) => {
if (!window.__MY_APP_CONFIG__) {
window.__MY_APP_CONFIG__ = value;
}
}, data);
If each navigation should receive the newest data, register a new hook or use a mutable value deliberately; do not assume an old document’s global survives navigation.
Choose the right Puppeteer API
| Need | API | Timing and behavior |
|---|---|---|
| Set a data value in the current document | page.evaluate |
Runs immediately in the current page context and returns a serialized result. |
| Expose a value before application startup | page.evaluateOnNewDocument |
Runs after document creation, before page scripts; applies again on navigation and child-frame attachment or navigation. |
| Let page code call Node.js | page.exposeFunction |
Adds a callable function to window. Calls cross back to a Node.js callback and resolve as Promises; the function survives navigation. |
| Retain a browser-side object reference | page.evaluateHandle |
Returns a JSHandle instead of copying the evaluated value into Node.js. |
exposeFunction is a bridge, not object injection
Use this when the page needs an operation implemented in Node.js:
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11await page.exposeFunction('lookupUser', async (id) => {
return { id, allowed: id === 123 };
});
Page code can call window.lookupUser(123) and receive a Promise. This does not create a static object such as window.user; it creates a function whose execution returns to Node.js.
Rank #3
When to use evaluateHandle
Use a handle when the object should remain represented in the browser, for example when it is large or when later operations need the same in-page reference:
const handle = await page.evaluateHandle((value) => ({ value }), data);
const value = await page.evaluate((object) => object.value, handle);
console.log(value);
await handle.dispose();
Handles are tied to a frame and execution context. Navigation disposes handles associated with the old document; explicitly dispose handles when finished to avoid retaining browser resources.
Data that does and does not serialize
Usually safe
- Plain objects and arrays.
- Strings, numbers, booleans and
null. - Nested combinations of those values.
Commonly problematic
- Functions: they are not transferred as callable Node.js functions. Use
exposeFunctionfor a Node callback. - Node-specific objects such as streams, sockets and class instances with behavior: pass the data fields you need instead.
- Circular references: convert them to an acyclic representation first.
- Live browser objects such as DOM nodes: obtain them in the page or use a JSHandle.
Dates, regular expressions, maps, sets and other special values need deliberate serialization if the receiving code must preserve their type. A JSON round trip can normalize data, but it also loses type information and may reject cycles:
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →const payload = JSON.parse(JSON.stringify(data));
await page.evaluate((value) => {
window.__PAYLOAD__ = value;
}, payload);
Do not interpolate serialized input into JavaScript source. Passing it as an argument avoids quoting errors and reduces injection risk when values contain apostrophes, newlines or user-controlled text.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Frames, navigation and timing
Navigation replaces the page context
A global belongs to one document. After page.goto(), a link click that navigates, or a reload, the new document has a new window. Inject again with evaluate(), or use evaluateOnNewDocument() when the value must be present on every navigation.
Child frames
The early-injection hook is invoked for newly attached or navigated child frames. A direct page.evaluate() targets the page’s main frame. To set a value in a particular iframe, obtain its frame and evaluate there:
const frame = page.frames().find((candidate) => candidate.url().includes('/checkout'));
if (!frame) throw new Error('Checkout frame was not found');
await frame.evaluate((value) => {
window.__CHECKOUT_CONFIG__ = value;
}, data);
Cross-origin restrictions still apply to what page scripts can access. A global placed in one frame is not automatically a global in another.
Debugging and failure modes
“My value is undefined”
- Wrong order: you read the global before the evaluation completed. Await the call.
- Navigation afterward: inject after the final navigation, or register
evaluateOnNewDocumentbefore navigating. - Wrong frame: evaluate in the frame that owns the code reading the value.
- Name collision: inspect
Object.prototype.hasOwnProperty.call(window, 'myData')and use a namespaced name.
“Cannot serialize” or a protocol error
Inspect the payload for cycles, functions, DOM nodes or unsupported host objects. Reduce it to plain data, or move the operation to exposeFunction or a handle. Log a compact summary in Node.js before passing it rather than dumping secrets into page logs.
Best Value
The site overwrites the property
Install before scripts with evaluateOnNewDocument, choose a less collision-prone name, or define a property descriptor appropriate to your application. A non-writable property can break sites that legitimately expect to assign that name, so use it only when you control the contract.
The value disappears after reload
That is expected for a normal page global. Re-register the new-document hook before the reload, or inject after every navigation event. Avoid assuming a JSHandle remains valid across navigation.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Testing the injection
Verify both presence and shape inside the browser:
const result = await page.evaluate(() => ({
present: Object.prototype.hasOwnProperty.call(window, '__MY_APP_CONFIG__'),
userId: window.__MY_APP_CONFIG__?.userId,
hasFlags: typeof window.__MY_APP_CONFIG__?.featureFlags === 'object'
}));
if (!result.present || result.userId !== 123 || !result.hasFlags) {
throw new Error(`Injection check failed: ${JSON.stringify(result)}`);
}
Run this check after the same navigation and frame selection used by the application. That catches timing errors that a test performed on about:blank would miss.
Recommended Free Tools
Or skip the browser setup
If your actual goal is a rendered screenshot rather than running Puppeteer yourself, ScreenshotNeo provides a website screenshot API and MCP server. A single GET request returns PNG, JPEG, WebP or PDF. Cookie and consent banners, newsletter popups and chat widgets are removed before capture; bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status.
cURL (see the ScreenshotNeo documentation):
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}`);
ScreenshotNeo also offers an MCP server for Claude, Cursor and other MCP clients, so an AI agent can call take_screenshot, get_page_info and capture_pdf. Every plan includes its features; the Free plan provides 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Does assigning to window make the object available to Node.js?
No. The assignment creates a browser-side global. To read it in Node.js, return a serializable value with page.evaluate or use a JSHandle.
Can I inject a class instance unchanged?
Do not rely on its prototype or methods crossing the boundary. Pass plain fields and reconstruct behavior in the page when necessary.
How do I remove an early-injection script?
Keep the identifier returned by the new-document registration and remove that script using Puppeteer’s documented removal method before registering a replacement.
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.

