Explain Codes LogoExplain Codes Logo

How can I pass a variable into an evaluate function?

javascript
evaluate-function
puppeteer
javascript-advanced
Alex KataevbyAlex Kataev·Feb 10, 2025
TLDR

To inject a variable into page.evaluate in Puppeteer, pass it as the second argument for the function. This sequence transfers the value from your Node.js environment to the paginated browser context:

const data = 'example'; await page.evaluate((injectedData) => { // Now you can use 'injectedData' in the browser context, so let's take it for a spin console.log(injectedData); // prints: 'example' }, data); // the 'example' we're passing; feel like Inception yet?

Handling multiple variables

Handling multiple variables? No problem, just provide additional arguments:

const name = 'Alice'; const age = 30; await page.evaluate((userName, userAge) => { // Use 'userName' and 'userAge' right here; it's a Puppeteer party! }, name, age);

Dealing with complex data types

For non-serializable objects or functions, use JSHandles or serialization:

await page.exposeFunction('myFunc', () => { console.log("All your base are belong to us!") }); await page.evaluate(async () => { await window.myFunc(); // prints: "All your base are belong to us!" });

Or serialize like a boss:

const complexFunction = function() { console.log("Can't touch this!") }; const stringifiedFunction = complexFunction.toString(); await page.evaluate(new Function(`return (${stringifiedFunction})();`)); // prints: "Can't touch this!"

Debugging cues

To debug within page.evaluate, use debugger; - it's literally a debug keyword:

// Brave enough to enter the Matrix, Neo? await page.evaluate(() => { debugger; // Triggers a breakpoint in browser code });

Remember to set { devtools: true } on launch, unless you're fond of Schroedinger's bug.

Console output and headless mode

Keep in mind, console.log() in page.evaluate() won't print in Node.js (they don't have that kind of relationship yet.) In headless mode, listen to the page.on('console') event:

page.on('console', msg => console.log('PAGE LOG:', msg.text()));

Scoping, serialization, and you

Serialization can behave like a boomerang with spikes if your variable includes functions or symbolic keys (JSON gives them the cold shoulder). Be careful with such variables! Stringify functions or use JSHandles to keep things smooth.

Case studies: Beyond the basics

Curious about object destructuring, explicit global function definition, or working in different browser contexts?

// Consider this scenario as object destructuring in practice const user = { name: 'Alice', age: 30 }; await page.evaluate(({ name, age }) => { // Now 'name' and 'age', once parts, now whole; it's like Voltron but with variables. }, user); // Here's your shiny global function definition: await page.evaluate(() => { window.myGlobalFunction = () => { console.log("Hello, World!")} ; }); // Marvel at your cosmopolitan creation. // And here's a quick sketch of working with different browser contexts: // (Reminder: DOM manipulations in Node.js? Nope. Not today, not ever.)

Pitfalls and parachutes

Going headfirst into scripting? Watch for these common pitfalls:

  • Scoping: Remember, what's declared outside of page.evaluate doesn't exist inside it unless you pass it as an argument.
  • Serialization: If your variable can't be serialized, expect errors. Meanwhile, JSON.stringify and JSHandles wait patiently by your side.
  • Event listeners: Those lovely events within page.evaluate? They're browser-scoped. Node.js can't hear them directly.