npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

n8n-nodes-playwright

v0.2.21

Published

n8n-community-node-package for browser automation using Playwright

Readme

n8n-nodes-playwright

This is an n8n community node. It lets you automate browser actions using Playwright in your n8n workflows.

n8n is a fair-code licensed workflow automation platform.

Installation
Operations
Custom Scripts
Compatibility
Resources
Version history

Installation

Follow the installation guide in the n8n community nodes documentation.

pnpm install n8n-nodes-playwright

Note: The package will automatically download and set up the required browser binaries during installation. This requires approximately 1GB of disk space.

If you need to manually trigger the browser setup:

pnpm rebuild n8n-nodes-playwright

Operations

This node supports the following operations:

Standard Operations

  • Navigate: Go to a specified URL and retrieve page content
  • Take Screenshot: Capture a screenshot of a webpage (full page or viewport)
  • Get Text: Extract text from an element using CSS selector or XPath
  • Click Element: Click on an element using CSS selector or XPath
  • Fill Form: Fill a form field using CSS selector or XPath
  • Run Custom Script: Execute custom JavaScript code with full Playwright API access

Browser Options

  • Choose between Chromium, Firefox, or WebKit
  • Configure headless mode
  • Adjust operation speed with slow motion option

Selector Options

For Get Text, Click Element, and Fill Form operations, you can choose between:

  • CSS Selector: Standard CSS selectors (e.g., #submit-button, .my-class, button[type="submit"])
  • XPath: XPath expressions (e.g., //button[@id="submit"], //div[contains(@class, "content")])

Screenshot Options

  • Full page capture
  • Custom save path
  • Base64 output

Custom Scripts

The Run Custom Script operation gives you complete control over Playwright to automate complex browser interactions, scrape data, generate PDFs/screenshots, and more. Scripts run in a sandboxed environment with access to the full Playwright API and n8n's Code node features.

Available Variables

Access Playwright-specific objects using:

  • $page - Current page instance
  • $browser - Browser instance
  • $playwright - Playwright library
  • $helpers - n8n helper methods (including prepareBinaryData)

Plus all special variables and methods from the Code node are available:

  • $json - Current item's JSON data
  • $input - Access to input data
  • $getNodeParameter() - Get node parameters
  • And more from n8n documentation

Script Examples

Basic Navigation and Data Extraction

// Navigate to a URL
await $page.goto('https://example.com');

// Get page title and content
const title = await $page.title();
const content = await $page.textContent('body');

console.log('Page title:', title);

// Return results
return [{
    json: { 
        title,
        content,
        url: $page.url()
    }
}];

Web Scraping with Selectors

await $page.goto('https://news.ycombinator.com');

// Scrape all story titles
const stories = await $page.$$eval('.titleline > a', elements => 
    elements.map(el => ({
        title: el.textContent,
        url: el.href
    }))
);

console.log(`Found ${stories.length} stories`);

return stories.map(story => ({ json: story }));

Form Automation

await $page.goto('https://example.com/login');

// Fill form fields
await $page.fill('#username', 'myuser');
await $page.fill('#password', 'mypass');

// Click submit button
await $page.click('button[type="submit"]');

// Wait for navigation
await $page.waitForNavigation();

console.log('Logged in successfully');

return [{
    json: {
        success: true,
        finalUrl: $page.url()
    }
}];

Taking Screenshots as Binary Data

await $page.goto('https://www.google.com');

// Take screenshot
const screenshot = await $page.screenshot({ 
    type: 'png',
    fullPage: true 
});

// Prepare binary data
const binaryData = await $helpers.prepareBinaryData(
    Buffer.from(screenshot),
    'screenshot.png',
    'image/png'
);

return [{
    json: {
        url: $page.url(),
        timestamp: new Date().toISOString()
    },
    binary: {
        screenshot: binaryData
    }
}];

Storing and Reusing Cookies

Script 1 - Login and Save Cookies

await $page.goto('https://www.example.com/login');

// Perform login
await $page.fill('#login-username', 'user');
await $page.fill('#login-password', 'pass');
await $page.click('#login-button');

// Wait for login to complete
await $page.waitForNavigation();

// Get browser context and save cookies
const context = $page.context();
const cookies = await context.cookies();

console.log('Login successful, cookies saved');

return [{
    json: { 
        cookies,
        loginSuccess: true
    }
}];

Script 2 - Restore Cookies and Access Protected Page

const { cookies } = $input.first().json;

// Create new context with saved cookies
const context = $page.context();
await context.addCookies(cookies);

// Navigate to authenticated page
await $page.goto('https://example.com/protected-page');

// Perform authenticated operations
const data = await $page.textContent('.protected-content');

console.log('Accessed protected page successfully');

return [{
    json: { 
        data,
        authenticated: true
    }
}];

Advanced: Multiple Operations

await $page.goto('https://example.com/products');

// Wait for products to load
await $page.waitForSelector('.product-item');

// Get all product data
const products = await $page.$$eval('.product-item', items =>
    items.map(item => ({
        name: item.querySelector('.product-name')?.textContent,
        price: item.querySelector('.product-price')?.textContent,
        image: item.querySelector('img')?.src
    }))
);

// Take a screenshot
const screenshot = await $page.screenshot({ type: 'png' });
const screenshotBinary = await $helpers.prepareBinaryData(
    Buffer.from(screenshot),
    'products.png',
    'image/png'
);

console.log(`Scraped ${products.length} products`);

return [{
    json: { 
        products,
        scrapedAt: new Date().toISOString(),
        totalProducts: products.length
    },
    binary: {
        screenshot: screenshotBinary
    }
}];

Using XPath Selectors

await $page.goto('https://example.com');

// Use XPath to find elements
const button = await $page.locator('xpath=//button[contains(text(), "Submit")]');
await button.click();

// XPath for complex selections
const items = await $page.locator('xpath=//div[@class="item" and @data-active="true"]').all();
const itemTexts = await Promise.all(items.map(item => item.textContent()));

console.log(`Found ${itemTexts.length} active items`);

return [{
    json: {
        activeItems: itemTexts
    }
}];

Error Handling

try {
    await $page.goto('https://example.com');
    
    // Try to find element with timeout
    const element = await $page.waitForSelector('.my-element', { 
        timeout: 5000 
    });
    
    const text = await element.textContent();
    
    return [{
        json: { 
            success: true,
            text 
        }
    }];
} catch (error) {
    console.error('Error occurred:', error.message);
    
    return [{
        json: {
            success: false,
            error: error.message
        }
    }];
}

Working with Multiple Pages

// Open a new page
const newPage = await $browser.newPage();
await newPage.goto('https://example.com/page2');

// Work with both pages
const page1Title = await $page.title();
const page2Title = await newPage.title();

console.log('Page 1:', page1Title);
console.log('Page 2:', page2Title);

// Close the new page
await newPage.close();

return [{
    json: {
        page1Title,
        page2Title
    }
}];

Generating PDFs

await $page.goto('https://example.com');

// Generate PDF
const pdf = await $page.pdf({
    format: 'A4',
    printBackground: true,
    margin: {
        top: '20px',
        right: '20px',
        bottom: '20px',
        left: '20px'
    }
});

// Prepare binary data
const binaryData = await $helpers.prepareBinaryData(
    Buffer.from(pdf),
    'document.pdf',
    'application/pdf'
);

return [{
    json: {
        url: $page.url(),
        timestamp: new Date().toISOString()
    },
    binary: {
        pdf: binaryData
    }
}];

Waiting for Dynamic Content

await $page.goto('https://example.com');

// Wait for network to be idle
await $page.waitForLoadState('networkidle');

// Wait for specific element to appear
await $page.waitForSelector('.dynamic-content', { timeout: 10000 });

// Wait for element to be visible
await $page.locator('.modal').waitFor({ state: 'visible' });

// Extract data after everything has loaded
const content = await $page.textContent('.dynamic-content');

return [{
    json: { content }
}];

Handling File Downloads

await $page.goto('https://example.com/downloads');

// Start waiting for download before clicking
const downloadPromise = $page.waitForEvent('download');
await $page.click('#download-button');

const download = await downloadPromise;

// Get download details
const fileName = download.suggestedFilename();
const downloadPath = await download.path();

console.log(`Downloaded: ${fileName}`);

return [{
    json: {
        fileName,
        downloadPath,
        success: true
    }
}];

Custom Script Tips

  1. Always return an array: Your script must return an array of objects like return [{ json: {...} }];
  2. Use console.log(): Debug by logging to the console - output appears in n8n UI during manual execution
  3. Handle errors: Use try-catch for robust scripts
  4. Binary data: Use $helpers.prepareBinaryData() for images, PDFs, or other files
  5. Async/await: All Playwright operations are async, always use await
  6. Access input data: Use $json or $input to access data from previous nodes
  7. Browser cleanup: The browser is automatically closed after script execution

Compatibility

  • Requires n8n version 1.0.0 or later
  • Tested with Playwright version 1.49.0
  • Supports Windows, macOS, and Linux

System Requirements

  • Node.js 18.10 or later
  • Approximately 1GB disk space for browser binaries
  • Additional system dependencies may be required for browser automation

Resources

Version history

0.3.0

  • Added Run Custom Script operation with full Playwright API access
  • Added XPath selector support for Get Text, Click Element, and Fill Form operations
  • Added sandboxed JavaScript execution environment
  • Improved error handling and user feedback
  • Fixed navigate operation to return page content properly

0.2.*

  • Added selector-based operations (getText, clickElement, fillForm)
  • Improved browser binary installation process
  • Bug fixes and performance improvements

0.1.*

  • Initial release
  • Basic browser automation operations
  • Support for Chromium, Firefox, and WebKit
  • Screenshot and navigation capabilities

Troubleshooting

Browsers Not Installed

If browsers are not installed correctly:

  1. Clean the installation:
rm -rf ~/.cache/ms-playwright
# or for Windows:
rmdir /s /q %USERPROFILE%\AppData\Local\ms-playwright
  1. Rebuild the package:
pnpm rebuild n8n-nodes-playwright

Custom Script Errors

If your custom script fails:

  1. Check that you're returning an array: return [{ json: {...} }];
  2. Use console.log() to debug and see output in n8n UI
  3. Wrap code in try-catch blocks for better error handling
  4. Verify all Playwright operations use await

Selector Not Found

If elements can't be found:

  1. Try using XPath instead of CSS selector (or vice versa)
  2. Use await $page.waitForSelector('selector') to wait for elements
  3. Check if content is in an iframe: await $page.frameLocator('iframe').locator('selector')
  4. Verify the page has fully loaded: await $page.waitForLoadState('networkidle')

License

MIT


Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

If you encounter any issues or have questions:

  1. Check the Troubleshooting section
  2. Review the Playwright documentation
  3. Open an issue on GitHub

Author

Mohamed Toema
Email: [email protected]
GitHub: @toema