Back to Nodes

Playwright

Last updated Mar 6, 2026

n8n-community-node-package for browser automation using Playwright with persistent browser session support

22 Weekly Downloads
100 Monthly Downloads

Included Nodes

Playwright

Description

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

  • n8n community nodes documentation
  • Playwright documentation
  • Playwright API Reference
  • 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%AppDataLocalms-playwright

2. 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: m.toema20@gmail.com
GitHub: @toema