I’m migrating from PhantomJS to Puppeteer and need help with setting up global variables before page loading starts. In PhantomJS, I used the onInitialized callback to inject window globals that were available right when the page began loading.
In Puppeteer, I can’t figure out the right timing. When I use evaluate() after creating a new page but before navigation, the variables get wiped out during page load. Using the domcontentloaded event is too late because the page scripts have already started running.
Here’s what I’m trying:
const browserInstance = await puppeteer.launch();
const newPage = await browserInstance.newPage();
// This gets cleared when navigation happens
await newPage.evaluate(config => {
window.appSettings = 'value1';
}, config);
newPage.on('domcontentloaded', event => {
newPage.evaluate(config => {
window.appSettings = 'value2'; // Page scripts already ran
}, config);
});
let response = await newPage.goto(targetUrl);
// This is definitely too late
await newPage.evaluate(config => {
window.appSettings = 'value3';
}, config);
What’s the Puppeteer equivalent for PhantomJS onInitialized timing?
heads up for anyone switching from phantomjs - timing’s a bit different with evaluateOnNewDocument(). phantomjs onInitialized fired before any network requests, but puppeteer runs after the document context gets created. not usually a problem but it tripped me up when dealing with early xhr calls in some apps.
You want addInitScript() - that’s exactly what you need. It runs JavaScript in every frame before any page scripts load, just like PhantomJS onInitialized.
evaluateOnNewDocument() runs before HTML parsing starts, so your globals are ready when page scripts execute. It’s the direct PhantomJS onInitialized equivalent. I’ve used this for browser automation and it works great across different page types.
Yeah, evaluateOnNewDocument() is the answer, but here’s something that tripped me up during migration. You need to call this before each navigation if you’re hitting multiple pages with the same page instance.
const page = await browser.newPage();
// This persists across navigations on this page instance
await page.evaluateOnNewDocument(() => {
window.myGlobal = 'persistent_value';
});
await page.goto('https://first-site.com');
await page.goto('https://second-site.com'); // myGlobal still available
One gotcha I hit: complex objects need to be serializable. If you need functions or complex data structures, stringify them first or rebuild them inside the evaluateOnNewDocument callback. Also works great with frames and iframes - way better than PhantomJS in my testing.