Back to Blog
best-practicesautomationperformance

Best Practices for Screenshot Automation

Learn best practices for automating screenshots at scale, including caching, error handling, and performance optimization.

BoltShot Team
April 16, 2026
Best Practices for Screenshot Automation

Best Practices for Screenshot Automation

When automating screenshots at scale, following best practices can help you save costs, improve performance, and ensure reliability.

Use Caching Wisely

Enable caching for screenshots that don't change frequently:

https://api.boltshot.dev/capture?url=https://example.com&cacheEnabled=true&cacheTtl=3600&apiKey=your-api-key

This can reduce processing time for repeated URLs. Caching is disabled by default (cacheEnabled=false) so you always get fresh screenshots unless you opt in.

Handle Errors Gracefully

Always implement proper error handling. By default, BoltShot returns the screenshot as a binary file (returnFile=true). Errors are always returned as JSON, even when you expect a binary response:

// Example 1: Default behavior — binary file response
async function takeScreenshot(url) {
  const params = new URLSearchParams({
    url,
    format: 'png',
    apiKey: process.env.BOLTSHOT_API_KEY,
  });

  const response = await fetch(`https://api.boltshot.dev/capture?${params}`);

  if (!response.ok) {
    const error = await response.json();
    // { success: false, error: { code, message, details } }
    throw new Error(error.error?.message || `API error: ${response.status}`);
  }

  return await response.blob();
}

try {
  const blob = await takeScreenshot('https://example.com');
  const imageUrl = URL.createObjectURL(blob);
} catch (error) {
  console.error('Screenshot failed:', error);
}

// Example 2: JSON response with returnFile=false
async function takeScreenshotJson(url) {
  const params = new URLSearchParams({
    url,
    format: 'png',
    returnFile: 'false',
    apiKey: process.env.BOLTSHOT_API_KEY,
  });

  const response = await fetch(`https://api.boltshot.dev/capture?${params}`);

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error?.message || `API error: ${response.status}`);
  }

  const result = await response.json();
  // { success: true, data: { url?, imageData?, fileName, ... } }
  return result.data;
}

try {
  const screenshotData = await takeScreenshotJson('https://example.com');
  // screenshotData.url when storage is configured
  // screenshotData.imageData is a data URL (data:image/png;base64,...)
} catch (error) {
  console.error('Screenshot failed:', error);
}

Optimize Viewport Sizes

Use appropriate viewport sizes for your use case. Larger viewports take more time and resources:

  • Thumbnails: 800x600
  • Standard: 1920x1080
  • High-res: 2560x1440

Prefer a device preset when you need realistic mobile or desktop rendering instead of only setting raw dimensions.

Respect Rate Limits

BoltShot enforces rate limits to ensure fair usage. The /capture endpoint allows 40 requests per minute. Implement rate limiting or request queuing in your application to stay under this cap.

Monitor Usage

Keep track of your API usage in the dashboard to stay within your plan limits. Each successful authenticated capture on /capture consumes one credit from your monthly allowance. Failed requests do not consume credits.

Check remaining credits programmatically:

https://api.boltshot.dev/usage?apiKey=your-api-key

Retry Logic

Implement exponential backoff for transient failures. Retry only on errors that may succeed on a second attempt (timeouts, 5xx), not on validation errors (4xx):

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function takeScreenshotWithRetry(url, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await takeScreenshot(url);
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await sleep(Math.pow(2, i) * 1000); // 1s, 2s, 4s
    }
  }
}

Use Storage Configurations

For production applications, configure S3-compatible storage in your dashboard (/dashboard/storage). When an active storage configuration exists, successful captures can return a permanent url in JSON mode instead of inline image data.

Pass a saved configuration per request with storageConfigId, or set one as the default for your organization. This reduces bandwidth in your app and gives you stable links for downstream workflows.

Following these practices will help you build reliable and efficient screenshot automation.