A Guide for Script Injection in Puppeteer

2/1/2025

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!

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!

Ready to Get Started?

Sign up now and start capturing stunning screenshots in minutes.

Sign Up Now