Browserless Puppeteer
Intro
During a recent migration of a service to Railway, we encountered a significant challenge with the Puppeteer package we were using for PDF generation. The package required numerous Linux dependencies, particularly for Linux-Chrome, which led to several issues:
- Dramatically increased build times
- Occasional build failures
- Numerous warnings and troubleshooting logs, guided by Puppeteer's documentation:
Initially, we considered creating a custom Dockerfile to manage these dependencies, as suggested in this Puppeteer/Chrome nixpacks example.
However, our continued research led us to a more elegant solution: Browserless. We discovered that we could integrate Browserless within Railway to handle Puppeteer calls and manage all the necessary dependencies. This approach proved to be significantly simpler than building a custom Dockerfile, and the implementation process was surprisingly straightforward.
The Migration
The migration ended up being a pretty easy process.
- Create a new Railway app and select the "Browserless" template.
- Update the
package.json
to remove thepuppeteer
dependency and instead use thepuppeteer-ci
package. (This does not include the chromium browser dependencies) - Include the new
BROWSER_WS_ENDPOINT
environment variable in the Railway app. - Update the code to connect to the Browserless instance. (see below)
const getBrowser = async () => { if (process.env.BROWSER_WS_ENDPOINT) { // Use Browserless for staging and production return await puppeteer.connect({ browserWSEndpoint: process.env.BROWSER_WS_ENDPOINT, }); } else { // Fallback to local Chrome instance if BROWSER_WS_ENDPOINT is not set for local development return await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox', '--headless=new'], ignoreDefaultArgs: ['--disable-extensions'], }); } }; const browser = await getBrowser(); // other logic here for generating PDFs const page = await browser.newPage(); // continue with PDF generation per normal
In the above code, we're checking for the BROWSER_WS_ENDPOINT
environment variable to be set. With this set, we can now leverage the connect
method of puppeteer to connect to the Browserless instance rather than launching a local browser instance.
That was it! We were now able to leverage Browserless for PDF generation and not have to worry about any of the dependencies.
Resources
Browserless isn't limited to Puppeteer; it's a versatile solution that also supports Playwright and Selenium. Consider exploring Browserless for your automation needs across these popular browser automation frameworks.