Why can't I access 'window' in an exposeFunction() function with Puppeteer?

mikemaccana picture mikemaccana · Jan 16, 2018 · Viewed 9.2k times · Source

I have a very simple Puppeteer script that uses exposeFunction() to run something inside headless Chrome.

(async function(){

    var log = console.log.bind(console),
        puppeteer = require('puppeteer');


    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    var functionToInject = function(){
        return window.navigator.appName;
    }

    await page.exposeFunction('functionToInject', functionToInject);

    var data = await page.evaluate(async function(){
        console.log('woo I run inside a browser')
        return await functionToInject();
    });

    console.log(data);

    await browser.close();

})()

This fails with:

ReferenceError: window is not defined

Which refers to the injected function. How can I access window inside the headless Chrome?

I know I can do evaluate() instead, but this doesn't work with a function I pass dynamically:

(async function(){

    var log = console.log.bind(console),
        puppeteer = require('puppeteer');

    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    var data = await page.evaluate(async function(){
        console.log('woo I run inside a browser')
        return window.navigator.appName;
    });

    console.log(data);

    await browser.close();

})()

Answer

mikemaccana picture mikemaccana · Jan 16, 2018

exposeFunction() isn't the right tool for this job.

From the Puppeteer docs

page.exposeFunction(name, puppeteerFunction)

puppeteerFunction Callback function which will be called in Puppeteer's context.

'In puppeteer's context' is a little vague, but check out the docs for evaluate():

page.evaluateHandle(pageFunction, ...args)

pageFunction Function to be evaluated in the page context

exposeFunction() doesn't expose a function to run inside the page, but exposes a function to be be run in node to be called from the page.

I have to use evaluate():