February 27, 2026 · 6 min read

Puppeteer Screenshot API:
Stop Managing Chrome Instances

You started with page.screenshot() and it worked great locally. Then you deployed it. Now you're dealing with Chrome crashes, zombie processes eating your RAM, Dockerfile nightmares with missing fonts, and that one page that hangs forever because of a rogue service worker.

Sound familiar? Here's the thing: you don't need to run Chrome yourself. A screenshot API does it for you, and your code gets simpler in the process.

The Puppeteer Tax

Running Puppeteer in production means maintaining a surprising amount of infrastructure:

The total cost isn't just the VPS. It's the engineer hours you spend debugging Chrome when you should be building your product.

Before and After

Here's what your Puppeteer screenshot code probably looks like:

const puppeteer = require('puppeteer');

async function takeScreenshot(url) {
  let browser;
  try {
    browser = await puppeteer.launch({
      headless: 'new',
      args: [
        '--no-sandbox',
        '--disable-setuid-sandbox',
        '--disable-dev-shm-usage',
        '--disable-gpu',
        '--single-process',
      ],
    });
    const page = await browser.newPage();
    await page.setViewport({ width: 1280, height: 800 });
    await page.goto(url, { 
      waitUntil: 'networkidle2',
      timeout: 30000 
    });
    // Wait for dynamic content
    await page.waitForTimeout(2000);
    const screenshot = await page.screenshot({ 
      type: 'png',
      fullPage: false 
    });
    return screenshot;
  } catch (error) {
    console.error('Screenshot failed:', error);
    throw error;
  } finally {
    if (browser) await browser.close().catch(() => {});
  }
}

Here's the same thing with a screenshot API:

const API_KEY = 'gs_your_api_key';

async function takeScreenshot(url) {
  const params = new URLSearchParams({
    url,
    apiKey: API_KEY,
    width: '1280',
    height: '800',
    format: 'png',
  });
  const res = await fetch(
    `https://grabshot.dev/v1/screenshot?${params}`
  );
  if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
  return Buffer.from(await res.arrayBuffer());
}

No browser launch. No sandbox flags. No cleanup. No zombie processes. The API handles all of that.

What You Get vs. What You Give Up

Self-hosted Puppeteer Screenshot API
Setup time Hours (Docker, fonts, sandbox) Minutes (get API key, call endpoint)
Infra cost $20-100/mo for a capable VPS $0-29/mo depending on volume
Concurrency Limited by RAM (3-10 concurrent) Handled by the service
Maintenance Chrome updates, dependency patches None
Custom JS execution Full control Limited (depends on API)
Page interaction Click, type, scroll - anything Basic (viewport, wait, scroll)

The trade-off is clear: if you need to click buttons, fill forms, or run complex page interactions before screenshotting, stick with Puppeteer. If you just need to capture how a URL looks, an API is dramatically simpler.

Migration Guide: Puppeteer to GrabShot API

Step 1: Get a free API key at grabshot.dev/dashboard (25 screenshots/month, no credit card).

Step 2: Replace your Puppeteer code. Map your options:

Puppeteer option GrabShot parameter
page.setViewport({width, height}) width, height
page.screenshot({fullPage: true}) fullPage=true
page.screenshot({type: 'jpeg'}) format=jpeg
page.waitForTimeout(ms) delay=ms
page.emulate(device) width=375&height=812 (set mobile dimensions)

Step 3: Remove Puppeteer from your dependencies and your Dockerfile. Enjoy the smaller container image.

When to Keep Puppeteer

A screenshot API isn't always the right choice. Keep Puppeteer if you need to:

For everything else - OG image generation, visual regression baselines, website thumbnails, PDF reports with page previews - an API call is simpler, cheaper, and more reliable than managing Chrome.

Quick Examples

cURL (simplest possible):

curl "https://grabshot.dev/v1/screenshot?url=https://github.com&apiKey=YOUR_KEY" \
  --output github.png

Python:

import requests

r = requests.get("https://grabshot.dev/v1/screenshot", params={
    "url": "https://github.com",
    "apiKey": "YOUR_KEY",
    "width": 1440,
    "format": "webp"
})
with open("github.webp", "wb") as f:
    f.write(r.content)

Node.js (with full-page capture):

const params = new URLSearchParams({
  url: 'https://github.com',
  apiKey: 'YOUR_KEY',
  fullPage: 'true',
  format: 'png',
});

const res = await fetch(
  `https://grabshot.dev/v1/screenshot?${params}`
);
const buffer = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('github-full.png', buffer);

Try it free

GrabShot gives you 25 free screenshots per month. No credit card, no trial expiration. Get your API key and start replacing Puppeteer in under a minute.