Migrate from Puppeteer to ScreenshotAPI

Step-by-step migration guide from Puppeteer to ScreenshotAPI. Parameter mapping, before/after code examples, and infrastructure savings.

Last updated: 2026-03-25

Try ScreenshotAPI free

5 free credits. No credit card required.

Start for free

Puppeteer is a powerful browser automation tool, but using it solely for screenshots introduces unnecessary complexity: Chrome binary management, memory leak handling, Docker image bloat, and scaling challenges. This guide walks through migrating your Puppeteer screenshot code to ScreenshotAPI.

Why Migrate

ConcernPuppeteerScreenshotAPI
Chrome binary~300 MB download, version managementCloud-managed
Docker image size1-1.5 GBNot needed
Memory per screenshot200-300 MB0 (HTTP call)
ScalingManual browser poolAutomatic
Zombie processesCommon, needs monitoringNot applicable
MaintenanceChrome updates, driver compatZero
Serverless compatibleNo (Chrome too large)Yes

Parameter Mapping

PuppeteerScreenshotAPINotes
page.setViewport({ width, height })width, heightQuery parameters
page.goto(url)urlQuery parameter
{ waitUntil: 'networkidle0' }waitUntil=networkidlenetworkidle0networkidle
{ waitUntil: 'load' }waitUntil=loadSame name
{ waitUntil: 'domcontentloaded' }waitUntil=domcontentloadedSame name
page.waitForSelector('#el')waitForSelector=#elQuery parameter
page.waitForTimeout(2000)delay=2000Milliseconds
{ fullPage: true }fullPage=trueQuery parameter
{ type: 'png' }type=pngpng, jpeg, webp
{ quality: 80 }quality=80JPEG/WebP only
page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }])colorScheme=darkSingle parameter

Before: Puppeteer

Basic screenshot

javascript
import puppeteer from 'puppeteer'; async function takeScreenshot(url) { const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); await page.setViewport({ width: 1440, height: 900 }); await page.goto(url, { waitUntil: 'networkidle0', timeout: 30000 }); const buffer = await page.screenshot({ type: 'png' }); await browser.close(); return buffer; }

Full-page with dark mode

javascript
async function takeFullPageDarkScreenshot(url) { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); await page.setViewport({ width: 1440, height: 900 }); await page.emulateMediaFeatures([ { name: 'prefers-color-scheme', value: 'dark' } ]); await page.goto(url, { waitUntil: 'networkidle0' }); const buffer = await page.screenshot({ fullPage: true, type: 'png' }); await browser.close(); return buffer; }

With selector waiting

javascript
async function screenshotAfterLoad(url, selector) { const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); await page.setViewport({ width: 1440, height: 900 }); await page.goto(url, { waitUntil: 'domcontentloaded' }); await page.waitForSelector(selector, { timeout: 10000 }); await page.waitForTimeout(500); const buffer = await page.screenshot({ type: 'png' }); await browser.close(); return buffer; }

After: ScreenshotAPI

Basic screenshot

javascript
async function takeScreenshot(url) { const params = new URLSearchParams({ url, width: '1440', height: '900', type: 'png', waitUntil: 'networkidle' }); const response = await fetch( `https://screenshotapi.to/api/v1/screenshot?${params}`, { headers: { 'x-api-key': process.env.SCREENSHOT_API_KEY } } ); if (!response.ok) throw new Error(`Screenshot failed: ${response.status}`); return Buffer.from(await response.arrayBuffer()); }

Full-page with dark mode

javascript
async function takeFullPageDarkScreenshot(url) { const params = new URLSearchParams({ url, width: '1440', fullPage: 'true', colorScheme: 'dark', type: 'png' }); const response = await fetch( `https://screenshotapi.to/api/v1/screenshot?${params}`, { headers: { 'x-api-key': process.env.SCREENSHOT_API_KEY } } ); return Buffer.from(await response.arrayBuffer()); }

With selector waiting

javascript
async function screenshotAfterLoad(url, selector) { const params = new URLSearchParams({ url, width: '1440', height: '900', type: 'png', waitUntil: 'domcontentloaded', waitForSelector: selector, delay: '500' }); const response = await fetch( `https://screenshotapi.to/api/v1/screenshot?${params}`, { headers: { 'x-api-key': process.env.SCREENSHOT_API_KEY } } ); return Buffer.from(await response.arrayBuffer()); }

Migration Steps

  1. Get an API key: Sign up at screenshotapi.to for 5 free credits
  2. Add the API key to your environment: Set SCREENSHOT_API_KEY in your .env
  3. Replace Puppeteer code: Swap browser.launch() + page.screenshot() with fetch() calls
  4. Remove Puppeteer dependency: npm uninstall puppeteer
  5. Remove Chrome from Docker: Delete Chromium-related layers from your Dockerfile
  6. Test: Verify screenshots match visually

Dockerfile Cleanup

Before

dockerfile
FROM node:20 RUN apt-get update && apt-get install -y \ chromium \ libnss3 \ libatk-bridge2.0-0 \ libdrm2 \ libxkbcommon0 \ libgbm1 \ --no-install-recommends ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium COPY . . RUN npm install CMD ["node", "server.js"]

After

dockerfile
FROM node:20-slim COPY . . RUN npm install CMD ["node", "server.js"]

Image size reduction: ~1.5 GB → ~200 MB.

Error Handling Comparison

Puppeteer (complex)

javascript
try { const browser = await puppeteer.launch(); // ... screenshot code ... } catch (error) { if (error.message.includes('Navigation timeout')) { // Page took too long to load } else if (error.message.includes('net::ERR_')) { // Network error } else if (error.message.includes('Protocol error')) { // Browser crashed } // Ensure browser is closed even on error await browser?.close(); }

ScreenshotAPI (simple)

javascript
const response = await fetch(apiUrl, { headers }); if (!response.ok) { const error = await response.text(); throw new Error(`Screenshot failed (${response.status}): ${error}`); }

No zombie processes, no browser cleanup, no memory leak monitoring.

Next Steps

Frequently asked questions

Why should I migrate from Puppeteer to a screenshot API?

Puppeteer requires managing Chrome binaries, handling memory leaks, scaling browser pools, and maintaining Docker images. A screenshot API handles all of this in the cloud, reducing infrastructure costs and engineering maintenance.

Can ScreenshotAPI do everything Puppeteer can?

For screenshot capture, yes. ScreenshotAPI supports all common Puppeteer screenshot features: viewport sizing, full-page capture, format selection, wait strategies, and device emulation. Puppeteer offers additional capabilities like form filling and cookie management that are outside the scope of a screenshot API.

How long does the migration take?

Typically 30-60 minutes. The migration involves replacing Puppeteer browser launch and screenshot code with HTTP requests. The URL, viewport, and wait parameters map directly.

Will screenshots look the same after migration?

Yes. ScreenshotAPI uses Chromium for rendering, the same browser engine as Puppeteer. The output is visually identical for the same URL and viewport settings.

Related resources

Start capturing screenshots today

Create a free account and get 5 credits to try the API. No credit card required. Pay only for what you use.