Scrnify blog
A Guide for Script Injection in Puppeteer
Hey there! Laura and Heidi here from SCRNIFY. Today, we're diving deep into script injection with Puppeteer. After spending countless hours working with browsers (and building a screenshot service along the way), we've learned a thing or two about injecting scripts effectively. Let's share what we've discovered!
If your Puppeteer setup exists mainly to capture pages, Scrnify is a website screenshot API that handles remote browser infrastructure for you.
The Basics: Your Script Injection Toolkit
Puppeteer gives us three main ways to inject scripts:
- By URL (loading from external sources)
- By file path (loading from your local system)
- Raw content (directly injecting JavaScript)
Let's explore each method with real, working examples.
Method 1: External Scripts via URL
const puppeteer = require('puppeteer')
async function injectExternalScript() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
try {
await page.goto('https://example.com')
// Inject jQuery from CDN
await page.addScriptTag({
url: 'https://code.jquery.com/jquery-3.7.1.min.js',
})
// Verify jQuery is working
const jQueryVersion = await page.evaluate(() => {
return jQuery.fn.jquery
})
console.log(`jQuery version ${jQueryVersion} injected successfully!`)
} finally {
await browser.close()
}
}
injectExternalScript().catch(console.error)
Console output:
jQuery version 3.7.1 injected successfully!
Method 2: Local File Injection
const puppeteer = require('puppeteer')
const path = require('path')
async function injectLocalScript() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
try {
await page.goto('https://example.com')
// Inject local script
await page.addScriptTag({
path: path.join(__dirname, 'custom-script.js'),
})
// Verify our custom function exists
const result = await page.evaluate(() => {
return window.myCustomFunction()
})
console.log('Custom script result:', result)
} finally {
await browser.close()
}
}
// custom-script.js content:
/*
window.myCustomFunction = function() {
return 'Hello from custom script!';
};
*/
injectLocalScript().catch(console.error)
Console output:
Custom script result: Hello from custom script!
Method 3: Raw Script Injection
const puppeteer = require('puppeteer')
async function injectRawScript() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
try {
await page.goto('https://example.com')
// Inject raw JavaScript
await page.addScriptTag({
content: `
window.modifyPage = function() {
document.body.style.backgroundColor = '#f0f0f0';
document.querySelector('h1').textContent = 'Modified!';
return 'Page modified successfully!';
};
`,
})
// Execute our injected function
const result = await page.evaluate(() => {
return window.modifyPage()
})
console.log('Script execution result:', result)
} finally {
await browser.close()
}
}
injectRawScript().catch(console.error)
Console output:
Script execution result: Page modified successfully!
Advanced Scenarios: Async Scripts and Security
Handling Async Scripts
const puppeteer = require('puppeteer')
async function handleAsyncScript() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
try {
await page.goto('https://example.com')
// Inject async script
await page.addScriptTag({
content: `
window.asyncOperation = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve('Async operation completed!');
}, 1000);
});
};
`,
})
// Wait for async operation
const result = await page.evaluate(async () => {
return await window.asyncOperation()
})
console.log('Async result:', result)
} finally {
await browser.close()
}
}
handleAsyncScript().catch(console.error)
Security Considerations
When injecting scripts, keep these high-level security practices in mind:
const puppeteer = require('puppeteer')
async function secureScriptInjection() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
try {
// Use content security policy
await page.setExtraHTTPHeaders({
'Content-Security-Policy': "script-src 'self' 'unsafe-inline' https://trusted-cdn.com",
})
await page.goto('https://example.com')
// Only inject from trusted sources
await page.addScriptTag({
url: 'https://trusted-cdn.com/script.js',
})
} finally {
await browser.close()
}
}
Comparing Methods: evaluate() vs addScriptTag()
Let's look at the key differences:
const puppeteer = require('puppeteer')
async function compareMethods() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
try {
await page.goto('https://example.com')
// Using evaluate()
const evaluateResult = await page.evaluate(() => {
document.body.style.backgroundColor = 'red'
return 'Modified with evaluate()'
})
console.log('Evaluate result:', evaluateResult)
// Using addScriptTag()
await page.addScriptTag({
content: `
document.body.style.backgroundColor = 'blue';
console.log('Modified with addScriptTag()');
`,
})
} finally {
await browser.close()
}
}
compareMethods().catch(console.error)
| Method | Execution | Best Used For | Behavior |
|---|---|---|---|
evaluate() |
Once | One-off operations | Executes and returns result |
addScriptTag() |
Persistent | Reusable functions | Remains in page context |
Performance Tips
Keep these general performance considerations in mind:
const puppeteer = require('puppeteer')
async function performanceOptimizedInjection() {
const browser = await puppeteer.launch()
const page = await browser.newPage()
try {
// Combine multiple scripts into one
await page.addScriptTag({
content: `
// All your functions in one injection
window.function1 = () => {};
window.function2 = () => {};
window.function3 = () => {};
`,
})
// Use async/defer for external scripts
await page.addScriptTag({
url: 'https://example.com/script.js',
type: 'text/javascript',
async: true,
})
} finally {
await browser.close()
}
}
Wrapping Up
Script injection in Puppeteer is powerful but requires careful consideration of your use case. Whether you're loading external libraries, injecting custom code, or handling async operations, always remember:
- Choose the right injection method for your needs
- Consider security implications
- Keep performance in mind
- Use error handling appropriate for your use case
We hope this guide helps you master script injection in Puppeteer! If you're looking for a ready-to-use solution for web captures, check out SCRNIFY - we've already handled all these complexities for you! 😉
Cheers, Laura & Heidi 🇦🇹
P.S. Got questions about Puppeteer or web automation? We'd love to hear from you!