DEV Community

Dan E
Dan E

Posted on • Originally published at rendex.dev

How to Make Screenshot APIs Fast: 5 Optimizations

How to Make Screenshot APIs Fast: 5 Optimizations

Most screenshot API calls take longer than they need to. The bottleneck is rarely the API itself. It is the choices you make when calling it: the output format, the viewport size, which resources the browser loads, and whether you send one request or fifty. Five adjustments cover the majority of avoidable overhead.

1. Use a compressed output format

PNG is lossless and therefore the largest output format by default. For thumbnails, preview cards, and social images where exact pixel accuracy is not required, WebP or JPEG cut file size by 50 to 80 percent with no perceptible quality loss at typical display sizes.

import { Rendex } from "@copperline/rendex"
import { writeFileSync } from "fs"

const rendex = new Rendex(process.env.RENDEX_API_KEY!)

// WebP — ~38 KB vs 210 KB for PNG
const webp = await rendex.screenshot({
  url: "https://example.com",
  format: "webp",
  quality: 82,
})

writeFileSync("capture.webp", webp.image)
Enter fullscreen mode Exit fullscreen mode

2. Right-size the viewport

The default viewport is 1280×800 at 2× device pixel ratio. For thumbnail generation, set width to your target size instead.

const thumb = await rendex.screenshot({
  url: "https://example.com",
  format: "webp",
  width: 400,
  height: 300,
  deviceScaleFactor: 1,
})
Enter fullscreen mode Exit fullscreen mode

3. Block resources you do not need

Third-party analytics scripts, font files, and video embeds add load time. Use blockResourceTypes to skip them.

const result = await rendex.screenshot({
  url: "https://dashboard.example.com",
  format: "webp",
  blockResourceTypes: ["font", "media", "other"],
})
Enter fullscreen mode Exit fullscreen mode

4. Choose the right wait strategy

waitUntil: "load" fires faster than the default "networkidle2" for server-rendered pages. Use waitForSelector for client-side apps.

// Fast server-rendered page
const result = await rendex.screenshot({
  url: "https://internal-dashboard.example.com",
  waitUntil: "load",
})

// SPA with async content
const spa = await rendex.screenshot({
  url: "https://app.example.com/dashboard",
  waitForSelector: "#main-content",
  waitUntil: "domcontentloaded",
})
Enter fullscreen mode Exit fullscreen mode

5. Submit multiple captures in one batch call

The batch endpoint accepts 5 to 500 URLs per call and processes them concurrently.

const batchResult = await rendex.batch({
  urls: productUrls,
  defaults: {
    format: "webp",
    quality: 82,
    width: 640,
    waitUntil: "load",
    blockResourceTypes: ["font", "media"],
  },
  webhookUrl: "https://yourapp.com/webhooks/screenshots",
})

console.log(batchResult.data.batchId)
Enter fullscreen mode Exit fullscreen mode

Troubleshooting

Page looks broken after blocking resources. Start with only "font" and "media". Pages that use web fonts for icons will break when fonts are blocked — inject a fallback with css: "* { font-family: sans-serif !important; }".

waitUntil: "load" returns a blank page. The page renders content after the load event. Use waitForSelector with a CSS selector that appears when content is ready.

Batch results have some failed jobs. Poll /v1/jobs/:jobId for each job. Failed jobs return an error code and message.

Next steps

Get a free API key (100 calls/month, no credit card) or see pricing for higher-volume plans.

Top comments (0)