---
title: "n8n Puppeteer Node Without Self-Hosting Chrome | Scrape.ly"
description: "The n8n Puppeteer node needs Chrome in your n8n container. How it and the Playwright nodes install, and how to run browser scrapes from n8n without it."
url: https://scrape.ly/blog/n8n-puppeteer-node
markdown: https://scrape.ly/blog/n8n-puppeteer-node.md
---

[Guides](https://scrape.ly/blog/category/guides.md)

# n8n Puppeteer Node: Puppeteer and Playwright in n8n Without Self-Hosting Chrome

The n8n Puppeteer node needs Chromium inside your n8n container and installs only on self-hosted n8n. How it and the Playwright nodes install, where they break, and how to run the same browser scrape on Scrape.ly from n8n instead, with a real tested run.

[Scrape.ly Team The team behind Scrape.ly](https://scrape.ly/blog/author/scrapely-team.md)

- Published

  Oct 28, 2026

- Reading time

  10 min read

![Pixel-art robot with an orange >\_ on its terminal head reaches out to drive a browser window showing the green Puppeteer and the Playwright logos, fed by a cable with data packets from a dark workflow node bearing the pink n8n logo](https://scrape.ly/media/n8n-puppeteer-node.png?w=1080)

The n8n Puppeteer node is `n8n-nodes-puppeteer`, a community node that drives a headless Chrome from your workflow: open a page, run a Puppeteer script, save a screenshot or a PDF. It works, but the browser has to live inside your n8n instance, and n8n installs unverified community nodes like this one only on self-hosted n8n.

That is where most searches for it start: a browser that won't launch, missing Chrome libraries, a custom Docker image. Below is the community-node route as it really is, for Puppeteer and Playwright, then what Browserless offers, then the route we recommend: run the browser on Scrape.ly and call it from n8n, so your n8n container never needs Chrome. We tested that route on a JavaScript-rendered page on 28 October 2026.

## n8n browser automation: your options at a glance

| Route                  | Where Chrome runs                                               | n8n Cloud                                                                                         | You write                                            | What comes back                                     |
| ---------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | --------------------------------------------------- |
| `n8n-nodes-puppeteer`  | Inside your n8n container, or a browser you host and connect to | No: unverified community nodes need self-hosting                                                  | A Puppeteer script                                   | What your script returns, plus screenshots and PDFs |
| `n8n-nodes-playwright` | Inside your n8n container (about 1 GB of browser binaries)      | No, same rule                                                                                     | Steps or a Playwright script                         | Page content, text, screenshots                     |
| Browserless            | Browserless's cloud or your own Browserless server              | The HTTP Request route works on any n8n                                                           | Endpoint calls, BrowserQL or a function              | The endpoint's response                             |
| Scrape.ly Actor        | Scrape.ly's cloud                                               | Yes: the Scrape.ly node is a verified community node, and the HTTP Request route works on any n8n | A page function, or nothing for a ready-made scraper | Rows, one n8n item each                             |

## What the n8n Puppeteer node does

[`n8n-nodes-puppeteer`](https://github.com/drudge/n8n-nodes-puppeteer) has four operations: get the full HTML of a page, capture it as a PDF, capture a screenshot, and run a custom script. The custom script gets `$page`, `$browser` and `$puppeteer` plus everything the Code node offers, so anything Puppeteer can do, the node can do.

The options are where it gets useful for scraping:

- **Stealth mode**, powered by `puppeteer-extra-plugin-stealth`. Our [Puppeteer stealth](https://scrape.ly/blog/puppeteer-stealth.md) test shows what that plugin patches and what it still leaves visible.
- **Proxy Server**, **Emulate Device**, **Extra Headers** and a navigation **Timeout**.
- **Browser WebSocket Endpoint**, to connect to a browser running somewhere else instead of launching one.
- **Capture Downloads**, which returns files a click downloads as binary data.

It also works as a tool for n8n AI agents: an agent can write the whole script through `$fromAI()`, or pass a URL into a fixed script as `$input.query`.

## How to install the n8n Puppeteer node, and where it breaks

On self-hosted n8n, an owner or admin goes to **Settings → Community Nodes → Install**, enters `n8n-nodes-puppeteer` and accepts the risks of unverified code. On n8n Cloud there is no such option. n8n's docs say it plainly: "Unverified community nodes aren't available on n8n cloud and require self-hosting n8n."

Installing the package is the easy part. The node launches Chrome in the same container as n8n, and that's where it breaks:

- **Missing system libraries.** Puppeteer downloads a Chromium on install, which, in the node's own words, "may not include necessary system dependencies". The README's troubleshooting section names errors about `libgobject-2.0.so.0` and `libnss3.so`. The top forum threads for this search read the same: "requires lib and chrome dependencies", "Failed to launch/connect to browser".
- **A custom Docker image.** The fix the README recommends for production is its own Docker setup: n8n plus Alpine's Chromium, fonts and libraries. Others publish ready images with Puppeteer and Chromium pre-installed. Either way, you now build your own n8n image and rebuild it whenever n8n updates.
- **Or a remote browser.** Set the Browser WebSocket Endpoint (or `PUPPETEER_BROWSER_WS_ENDPOINT`) to a Chrome you run elsewhere. That removes the libraries from n8n, but you still host a browser, and you still need self-hosted n8n for the node.

Don't expect the node on n8n Cloud soon, either. n8n's verification guidelines require a package with no external dependencies that never reads environment variables or files. A node that bundles Puppeteer and reads `PUPPETEER_*` variables doesn't fit those rules as written.

## The n8n Playwright node

The Playwright side looks the same. [`n8n-nodes-playwright`](https://github.com/toema/n8n-playwright) offers Navigate, Take Screenshot, Get Text, Click Element, Fill Form and Run Custom Script, in Chromium, Firefox or WebKit. It downloads the browser binaries during installation, which "requires approximately 1GB of disk space", and its README warns that "additional system dependencies may be required". It's an unverified community node too, so self-hosted only.

Search results for "n8n playwright node" also turn up forks for persistent sessions and for running raw Playwright code, plus a forum thread about the node's paths on macOS. Picking a library won't save you the hosting work; if you are still choosing, our [Playwright vs Puppeteer](https://scrape.ly/blog/playwright-vs-puppeteer.md) and [Puppeteer vs Selenium](https://scrape.ly/blog/puppeteer-vs-selenium.md) comparisons cover the differences that matter for scraping.

## Run the browser on Scrape.ly instead

The browser doesn't have to run in n8n at all. On Scrape.ly, an Actor is a cloud program that takes JSON input and returns rows. The [Web Scraper](https://scrape.ly/store/querystone/web-scraper.md) Actor with `useChrome` turned on loads each page in Chromium, waits until the network goes quiet, and runs your page function on the DOM after the page's scripts have run. That's the job most people install the Puppeteer node for.

The Chrome runs on Scrape.ly's side: our run's log shows the launch redirected to a remote browser. Pages load through Scrape.ly's residential proxy by default, and you pay per row of data, platform usage included. For popular sites, the [Scrape.ly Store](https://scrape.ly/store.md) has 570+ ready-made Actors that return structured data with no page function at all. If headless browsers are new to you, [what is a headless browser](https://scrape.ly/blog/what-is-a-headless-browser.md) explains what is happening on the other end.

From n8n you call the Actor in one of two ways.

### Option 1: the Scrape.ly n8n node

The `n8n-nodes-scrapely` community node is an API client only: no browser, no runtime dependencies. That's why n8n verified it, so it installs on n8n Cloud and self-hosted n8n alike, straight from the nodes panel:

1. In n8n, open the nodes panel, search for **Scrapely** and pick the version with the verified badge, then click **Install** (an instance owner or admin does this once). Self-hosted instances can also install `n8n-nodes-scrapely` under **Settings → Community nodes → Install**.
2. Create a **Scrapely API** credential with an API token from the Scrape.ly dashboard (**Settings → API & Integrations**). A scoped key needs `actors:run`, `runs:read` and `datasets:read`.
3. Add the **Scrapely** node with **Resource** Actor and **Operation** Run. Pick the Actor from the searchable list or type its ID, `querystone/web-scraper`, and paste the input JSON shown below.
4. Leave **Wait for Finish** and **Return Results** on. The node waits up to **Max Wait** (3,600 seconds by default), then outputs each row as one n8n item, up to **Results Limit** (1,000 by default).

The same node works as a tool for n8n AI agents. The **Scrapely Trigger** starts a workflow when a run succeeds, fails, times out or is aborted, and with **Include Results** on it hands you the rows instead of the event. The [n8n docs page](https://scrape.ly/docs/n8n.md) lists every operation, and our [n8n web scraping guide](https://scrape.ly/integrations/n8n.md) has example workflows.

### Option 2: the HTTP Request node, on any n8n

The HTTP Request node is built into n8n, so this route also works on n8n Cloud. It calls the run-sync endpoint, which starts the run, waits for it and returns the rows as a JSON array:

```shell
curl -X POST "https://api.scrape.ly/v2/actors/querystone~web-scraper/run-sync-get-dataset-items?maxTotalChargeUsd=0.05"
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
  -H "Content-Type: application/json"
  -d @input.json
```

In the node, that is:

| Setting           | Value                                                                                                      |
| ----------------- | ---------------------------------------------------------------------------------------------------------- |
| Method            | POST                                                                                                       |
| URL               | `https://api.scrape.ly/v2/actors/querystone~web-scraper/run-sync-get-dataset-items?maxTotalChargeUsd=0.05` |
| Authentication    | Generic Credential Type, Header Auth: header `Authorization`, value `Bearer` plus your API token           |
| Send Body         | On, Body Content Type JSON, Specify Body Using JSON, with the input below                                  |
| Options → Timeout | 60000 (milliseconds), so n8n waits out the sync window                                                     |

`maxTotalChargeUsd` caps what the run can spend. The endpoint waits up to 45 seconds. If a run takes longer, it answers `408` and the run keeps going; don't call the endpoint again, because that starts a second run. Jobs that regularly run longer belong in the Scrape.ly node, which waits until the run finishes. The [Actors API docs](https://scrape.ly/docs/api-actors.md) list every endpoint.

## A real run: a JavaScript page in Chrome, two pages deep

[quotes.toscrape.com/js](https://quotes.toscrape.com/js/) is a practice site whose quotes don't exist in the HTML: a script writes them into the page. Fetch it with the HTTP Request node and you get no quotes. This is the input we sent, the same body the node or the HTTP Request node sends:

```json
{
  "startUrls": [{ "url": "https://quotes.toscrape.com/js/" }],
  "useChrome": true,
  "linkSelector": "li.next a",
  "maxPagesPerCrawl": 2,
  "pageFunction": "async function pageFunction(context) {\n    const $ = context.jQuery;\n    return $('.quote').map((i, el) => ({\n        page: context.request.url,\n        text: $(el).find('.text').text(),\n        author: $(el).find('.author').text(),\n        tags: $(el).find('.tag').map((j, t) => $(t).text()).get(),\n    })).get();\n}",
  "respectRobotsTxtFile": true,
  "proxyConfiguration": { "useScrapelyProxy": true }
}
```

The page function, readable:

```javascript
async function pageFunction(context) {
    const $ = context.jQuery;
    return $('.quote').map((i, el) => ({
        page: context.request.url,
        text: $(el).find('.text').text(),
        author: $(el).find('.author').text(),
        tags: $(el).find('.tag').map((j, t) => $(t).text()).get(),
    })).get();
}
```

`useChrome` renders each page in Chromium, `linkSelector` follows the "Next" link, and `maxPagesPerCrawl` stops after two pages. The run (ID `540abbc8542d49858`) logged:

```plaintext
20261028T13:32:18.191Z [scrapely.actor] INFO  Done: 2 pages fetched, 20 records saved, Chrome avg per page: open 0.6s goto 0.8s idle 0.5s scroll 0.7s snapshot 0.2s in 13 s
20261028T13:32:18.191Z [scrapely.actor] INFO  [Status message]: Saved 20 results from 2 pages. Stopped at Max pages per run (2); raise it to crawl more.
```

It returned 20 rows, ten from each page, in 16 seconds end to end, well inside the 45-second sync window. A few of them:

| page        | author          | text                                                                                                                | tags                                   |
| ----------- | --------------- | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| /js/        | Albert Einstein | "The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking." | change, deep-thoughts, thinking, world |
| /js/        | J.K. Rowling    | "It is our choices, Harry, that show what we truly are, far more than our abilities."                               | abilities, choices                     |
| /js/        | Marilyn Monroe  | "Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring."     | be-yourself, inspirational             |
| /js/page/2/ | Albert Einstein | "If you can't explain it to a six year old, you don't understand it yourself."                                      | simplicity, understand                 |

In n8n, each of those rows arrives as one item, ready for Google Sheets, a database or an AI step. The 20 rows cost from $0.01144. For more ways to handle pages like this, see [how to scrape dynamic websites](https://scrape.ly/blog/scrape-dynamic-websites.md).

## Porting a Puppeteer script to a page function

Most Puppeteer-node scripts for scraping map onto Web Scraper fields:

| In the Puppeteer node              | In the Web Scraper                                         |
| ---------------------------------- | ---------------------------------------------------------- |
| `$page.goto(url)`                  | `startUrls`                                                |
| `waitUntil: 'networkidle2'`        | `waitUntil`, `networkidle2` by default                     |
| `$page.$$eval()` over a selector   | jQuery in the page function (`context.jQuery`)             |
| A loop that clicks "Next"          | `linkSelector` with `maxPagesPerCrawl`                     |
| Clicking or typing before you read | A post-navigation hook, which receives the Chromium `page` |
| The Proxy Server option            | `proxyConfiguration`, residential by default               |
| `return [...]`                     | Each returned object becomes one row                       |

Scrolling for lazy content is built in (`maxScrollHeightPixels`), and so is dismissing cookie dialogs (`closeCookieModals`).

## Where the Browserless node fits

Browserless runs Chrome as a hosted service, or as a container you run yourself, and the Puppeteer node's README lists it among the browsers you can point the WebSocket endpoint at. From n8n you can call it two ways. Its own docs give HTTP Request templates for screenshots, PDFs, page content, unblocking, CSS-selector scraping, BrowserQL and custom functions, with the API token as a query parameter. And Browserless publishes a community node, `n8n-nodes-browserless-api`, with operations such as Smart Scrape, Screenshot, PDF, Crawl, Run Function and Run Agent.

It's a good fit if you want a remote browser and plan to keep writing browser code. Scrape.ly takes you one step further: you pay for rows of data rather than a browser, and for popular sites a ready-made Store Actor already returns structured fields, with no browser code for you to keep working when the site changes.

## What it costs

The Web Scraper charges one event per row your page function returns, platform usage (compute, proxy and browser) included. Price checked on the Store page on 28 October 2026: **from $0.572 per 1,000 results**, whether a page loads over HTTP or in Chrome. Pages that return nothing aren't charged.

Our run returned 20 rows, which cost from $0.01144. The Free plan's $5 of monthly usage covers about 6,900 results, with no credit card. Paid plans and their limits are on the [pricing page](https://scrape.ly/pricing.md). There's no Chrome server to pay for or patch.

## FAQ

### Can I use the Puppeteer node on n8n Cloud?

No. n8n Cloud runs only verified community nodes, and `n8n-nodes-puppeteer` isn't one. To drive a browser from n8n Cloud, install the verified Scrapely node from the nodes panel and run a browser Actor such as the Web Scraper, or call the same Actor through the built-in HTTP Request node with the request shown above.

### Does the Scrape.ly node work on n8n Cloud?

Yes. `n8n-nodes-scrapely` is a verified community node, so an owner or admin can install it from the nodes panel on n8n Cloud or self-hosted n8n: search for **Scrapely**, pick the version with the verified badge and click **Install**.

### Is there an n8n Playwright node?

Not a built-in one. `n8n-nodes-playwright` is a community node with navigate, click, fill, text, screenshot and custom-script operations. It downloads about 1 GB of browser binaries on install and runs on self-hosted n8n only.

### How do I add Puppeteer to n8n in Docker?

Build an image that adds Chromium, its fonts and libraries to the n8n image, then install `n8n-nodes-puppeteer` in it. The node's repository includes a Docker setup for this. The alternative is to point the node's Browser WebSocket Endpoint at a browser running in another container, or to skip both and run the browser on Scrape.ly.

### Why does n8n-nodes-puppeteer fail to launch the browser?

Usually because Chrome's system libraries are missing from the n8n container: errors name files such as `libnss3.so`. Install the dependencies, use an image with Chromium included, or connect to a remote browser.

### Does n8n have a built-in browser automation node?

No. n8n's core nodes include HTTP Request, HTML and Code, but no headless browser. The HTTP Request node fetches a page's HTML without running its JavaScript, which is why it finds no quotes on the page in our run.

### Can an n8n AI agent control a browser?

Yes, through a tool. The Puppeteer node can run as an agent tool with an AI-written script. The Scrape.ly node also works as an agent tool, so an agent can run a browser-backed Actor and read the rows it returns.

Scrape.ly Store Run Chrome from n8n without installing it Render JavaScript pages in a hosted Chrome, run your page function and get the rows back as n8n items. From $0.572 per 1,000 results, platform usage included.

[Try it free](https://scrape.ly/store/querystone/web-scraper.md) [Browse the Store](https://scrape.ly/store.md)

About the author

[Scrape.ly Team](https://scrape.ly/blog/author/scrapely-team.md) The team behind Scrape.ly

Scrape.ly is the web data platform from TeraShift GmbH in Switzerland, powered by Evomi: ready-made scrapers in the Scrape.ly Store, a cloud runtime, an API with JavaScript and Python SDKs, proxies, a hosted anti-bot browser and an MCP server for AI agents.

- [Website](https://scrape.ly/index.md)

Keep reading

## More in Guides

- [![Pixel-art robot with an orange >\_ on its terminal head stands thinking between two matching arcade cabinets, one with the green Puppeteer logo and one with the green Selenium logo, next to a crate bearing the Scrape.ly logo](https://scrape.ly/media/puppeteer-vs-selenium.png?w=750)](https://scrape.ly/blog/puppeteer-vs-selenium.md)
  ### [Puppeteer vs Selenium for Web Scraping: The Same Scraper in Both](https://scrape.ly/blog/puppeteer-vs-selenium.md)
  [Puppeteer vs Selenium for web scraping: languages, browsers, protocols, waiting, request blocking and parallel sessions, from the official docs on 28 October 2026, plus the same scraper written in Puppeteer and Selenium and tested on a JavaScript-rendered page.](https://scrape.ly/blog/puppeteer-vs-selenium.md)
- [![Pixel-art robot with an orange >\_ on its terminal head reaches up to take a JSON card with curly braces from a hook at the end of a cable that runs from a server rack, an amber bell ringing on top of the rack, a crate beside it](https://scrape.ly/media/webhooks-for-scraping.png?w=750)](https://scrape.ly/blog/webhooks-for-scraping.md)
  ### [Get Notified When a Scrape Finishes: Webhooks, Slack and Email](https://scrape.ly/blog/webhooks-for-scraping.md)
  [How to use webhooks for web scraping: get an HTTP call, a Slack or Discord message or an email the moment a scraper run finishes, with the run and dataset IDs to fetch results. Event types, payload templates, retries, a tested Python receiver and the API calls to set it up.](https://scrape.ly/blog/webhooks-for-scraping.md)
- [![Pixel-art robot with an orange >\_ on its terminal head pulls a data card out of a board headed by the Zapier logo, whose three linked steps show an orange lightning bolt, a web page and a green sheet, and drops it into a crate](https://scrape.ly/media/zapier-web-scraping.png?w=750)](https://scrape.ly/blog/zapier-web-scraping.md)
  ### [Web Scraping With Zapier: Send Scraped Data Anywhere](https://scrape.ly/blog/zapier-web-scraping.md)
  [How to connect web scraping to Zapier: start a Scrape.ly scraper from a Zap, catch the results when a run finishes, and send rows to Google Sheets, Slack, a CRM or any of Zapier's apps. Step-by-step recipes, the request each step sends, and when you don't need Zapier at all.](https://scrape.ly/blog/zapier-web-scraping.md)

## The internet is full of data. Start owning yours.

Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes.

[Get Started Free](https://my.scrape.ly/register) [Chat with Support](mailto:hello@scrape.ly?subject=Question%20about%20Scrape.ly\&body=Hi%2C%20I%20have%20a%20question%20about%20Scrape.ly.)

No credit card. No setup calls.
