Migrate from Playwright to ScreenshotAPI

Replace Playwright screenshot code with ScreenshotAPI. Parameter mapping table, before/after examples, and Docker image reduction guide.

Last updated: 2026-03-25

Try ScreenshotAPI free

5 free credits. No credit card required.

Start for free

Playwright is an excellent testing framework, but using it solely for screenshot capture means managing browser binaries, handling memory usage, and maintaining Docker images with hundreds of megabytes of browser dependencies. If screenshots are your only use case, migrating to ScreenshotAPI eliminates that overhead.

Parameter Mapping

PlaywrightScreenshotAPINotes
viewport: { width, height }width, heightQuery parameters
page.goto(url)urlQuery parameter
waitUntil: 'networkidle'waitUntil=networkidleSame value
waitUntil: 'load'waitUntil=loadSame value
waitUntil: 'domcontentloaded'waitUntil=domcontentloadedSame value
page.waitForSelector(sel)waitForSelector=selQuery parameter
fullPage: truefullPage=trueQuery parameter
type: 'png'type=pngpng, jpeg, webp
quality: 80quality=80JPEG/WebP only
colorScheme: 'dark'colorScheme=darkContext → query param
page.waitForTimeout(ms)delay=msMilliseconds

Before: Playwright

Basic screenshot

javascript
import { chromium } from 'playwright'; async function takeScreenshot(url) { const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); await page.goto(url, { waitUntil: 'networkidle' }); const buffer = await page.screenshot({ type: 'png' }); await browser.close(); return buffer; }

Dark mode full-page

javascript
async function takeFullPageDark(url) { const browser = await chromium.launch(); const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, colorScheme: 'dark' }); const page = await context.newPage(); await page.goto(url, { waitUntil: 'networkidle' }); const buffer = await page.screenshot({ fullPage: true, type: 'png' }); await browser.close(); return buffer; }

Multiple viewports

javascript
async function captureViewports(url) { const browser = await chromium.launch(); const results = {}; for (const vp of [ { name: 'desktop', width: 1440, height: 900 }, { name: 'tablet', width: 768, height: 1024 }, { name: 'mobile', width: 375, height: 812 }, ]) { const page = await browser.newPage({ viewport: { width: vp.width, height: vp.height } }); await page.goto(url, { waitUntil: 'networkidle' }); results[vp.name] = await page.screenshot({ type: 'png' }); await page.close(); } await browser.close(); return results; }

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()); }

Dark mode full-page

javascript
async function takeFullPageDark(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()); }

Multiple viewports (parallel)

javascript
async function captureViewports(url) { const viewports = [ { name: 'desktop', width: '1440', height: '900' }, { name: 'tablet', width: '768', height: '1024' }, { name: 'mobile', width: '375', height: '812' }, ]; const captures = viewports.map(async (vp) => { const params = new URLSearchParams({ url, width: vp.width, height: vp.height, type: 'png', waitUntil: 'networkidle' }); const response = await fetch( `https://screenshotapi.to/api/v1/screenshot?${params}`, { headers: { 'x-api-key': process.env.SCREENSHOT_API_KEY } } ); return [vp.name, Buffer.from(await response.arrayBuffer())]; }); return Object.fromEntries(await Promise.all(captures)); }

With the API, multiple viewports can be captured in parallel without managing separate browser contexts.

Incremental Migration

Create a wrapper that supports both backends:

javascript
const USE_API = process.env.SCREENSHOT_BACKEND === 'api'; async function takeScreenshot(url, options = {}) { if (USE_API) { return takeScreenshotAPI(url, options); } return takeScreenshotPlaywright(url, options); }

Toggle with SCREENSHOT_BACKEND=api when ready.

Migration Steps

  1. Sign up at screenshotapi.to and get an API key
  2. Add wrapper: Create a screenshot function that supports both backends
  3. Test in parallel: Run both backends and compare output visually
  4. Switch: Set the environment variable to use the API
  5. Remove Playwright: npm uninstall playwright @playwright/test
  6. Clean Docker: Remove npx playwright install and browser deps from Dockerfile

Infrastructure Savings

Before (Playwright Docker)

dockerfile
FROM mcr.microsoft.com/playwright:v1.42.0-jammy COPY . . RUN npm ci CMD ["node", "server.js"]

Image size: ~1.2 GB

After (API-based)

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

Image size: ~200 MB

When to Keep Playwright

Keep Playwright if you also use it for:

  • End-to-end testing (use Playwright for tests, API for production screenshots)
  • Form automation and multi-step navigation flows
  • Cookie injection and authentication flows
  • JavaScript execution before screenshot (custom scripts)

Next Steps

Frequently asked questions

Is Playwright or ScreenshotAPI better for screenshots?

Playwright is better if you need full browser automation (form filling, navigation, testing). ScreenshotAPI is better if you only need to capture screenshots, because it eliminates infrastructure overhead.

Does ScreenshotAPI support Playwright's wait strategies?

Yes. Playwright's waitUntil: networkidle maps to waitUntil=networkidle in ScreenshotAPI. Playwright's waitForSelector maps to the waitForSelector parameter. The colorScheme context option maps to the colorScheme parameter.

How much smaller will my Docker image be?

Removing Playwright and its browser binaries typically reduces Docker image size from 800 MB-1.2 GB to under 200 MB.

Can I migrate incrementally?

Yes. Create a wrapper function that supports both backends. Use an environment variable to toggle between Playwright and ScreenshotAPI during your migration period.

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.