How to Take Screenshots in Playwright Without Managing a Browser
Take website screenshots with Playwright's reliability without managing a browser in CI or production. One API call. No browser overhead.
You're using Playwright to automate browser tasks. It's fast, reliable, and works everywhere. But when you add screenshots to your workflow, you hit a wall:
Self-hosted Playwright screenshots are expensive.
Browser instances consume memory. CI pipelines timeout. Serverless functions can't spin up Chromium. Every screenshot adds seconds to your automation.
There's a simpler way: use a screenshot API.
One HTTP request. Binary PNG back. No browser management. No memory overhead. No vendor lock-in.
The Problem: Self-Hosted Playwright Screenshots Are Heavy
Playwright is great for automation. But screenshots come with a cost.
// Self-hosted Playwright: screenshot costs resources
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
// This keeps the browser running in memory
const screenshot = await page.screenshot({ path: 'screenshot.png' });
await browser.close();
What this costs:
- Memory: 100–300MB per browser instance
- Time: 2–5 seconds to launch + navigate
- Complexity: Error handling, cleanup, retry logic
- Scalability: CI runners choke on multiple simultaneous screenshots
- Cost: Serverless functions are billed for entire browser lifetime
If you're taking 100 screenshots, you're spinning up 100 browser instances. Each one eats memory and time.
The Solution: Screenshot API
One API call. No browser.
// Hosted API: screenshot in one request
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': `${process.env.PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://example.com',
format: 'png',
width: 1280,
height: 720
})
});
const buffer = await response.arrayBuffer();
const screenshot = Buffer.from(buffer);
// Done. No browser. No memory overhead.
What you get:
- Speed: One HTTP request (50–200ms)
- Simplicity: No browser management
- Scalability: Unlimited concurrent screenshots
- Reliability: Automatic retries, global CDN
- Cost: $0–199/month based on volume
Playwright + API: Best of Both Worlds
Use Playwright for automation. Use API for screenshots.
// Playwright for automation, API for proof
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
// Navigate and interact with Playwright
await page.goto('https://example.com/checkout');
await page.fill('input[name="email"]', 'user@example.com');
await page.click('button:has-text("Checkout")');
await page.waitForNavigation();
// Take screenshot via API (no extra browser needed)
const finalUrl = page.url();
const screenshotResponse = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': `${process.env.PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: finalUrl,
format: 'png'
})
});
const buffer = await screenshotResponse.arrayBuffer();
// Use screenshot for verification, logging, etc.
await browser.close();
You still use Playwright. But you don't spin up a separate browser just for screenshots.
Comparison: Self-Hosted vs. API
| Factor | Self-Hosted Playwright | Screenshot API |
|---|---|---|
| Setup | 10 min (install deps) | 2 min (API key) |
| Code complexity | 20+ lines per screenshot | 5–8 lines |
| Memory per screenshot | 150–300MB | 0MB |
| Time per screenshot | 2–5 sec | 0.1–0.3 sec |
| CI/serverless support | Difficult (timeout, resource limits) | Works everywhere |
| Scaling to 1,000 screenshots | Requires parallelization, resource limits | Unlimited concurrency |
| Error handling | Custom retry logic needed | Built-in retries |
| Cost | Free (hardware) | $0–199/month |
Real Use Case: E-Commerce Order Confirmation
Playwright handles the business logic. API handles the screenshot.
import { chromium } from 'playwright';
async function captureOrderConfirmation(orderId) {
const browser = await chromium.launch();
const page = await browser.newPage();
// Playwright: Navigate to order confirmation
await page.goto(`https://example.com/orders/${orderId}`);
// Wait for confirmation to render
await page.waitForSelector('.order-confirmation');
// API: Take screenshot of final state
const screenshotResponse = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': `${process.env.PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: page.url(),
format: 'png',
fullPage: true,
blockBanners: true // Hide cookie popups
})
});
const buffer = await screenshotResponse.arrayBuffer();
// Store for audit trail
const filename = `order-${orderId}-confirmation.png`;
fs.writeFileSync(filename, Buffer.from(buffer));
await browser.close();
return filename;
}
What this gives you:
- ✅ Playwright's reliability for navigation
- ✅ API's speed for screenshots
- ✅ One browser instance (not two)
- ✅ Fast, lightweight workflow
Real Use Case: Headless Test Reports
Testing framework + API = visual test reports.
import { test, expect } from '@playwright/test';
test('checkout flow creates confirmation', async ({ page }) => {
// Test with Playwright
await page.goto('https://example.com');
await page.fill('input[name="email"]', 'test@example.com');
await page.click('button:has-text("Next")');
// Assert behavior
await expect(page).toHaveURL(/confirmation/);
// Capture proof screenshot
const screenshotResponse = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': `${process.env.PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: page.url(),
format: 'png'
})
});
const buffer = await screenshotResponse.arrayBuffer();
await fs.promises.writeFile(`test-${Date.now()}-proof.png`, Buffer.from(buffer));
});
Tests pass/fail as usual. But you have visual proof of what the page looked like when the test ran.
API Parameters (Playwright Common Use Cases)
| Parameter | Example | Use Case |
|---|---|---|
| url | page.url() |
Screenshot current page |
| format | png |
PNG format (supports pdf, webp) |
| fullPage | true |
Capture entire scrollable page |
| width | 1280 |
Viewport width (desktop) |
| height | 720 |
Viewport height |
| blockBanners | true |
Hide cookie consent popups |
| blockAds | true |
Remove ads for clean screenshots |
Error Handling
async function safeScreenshot(url) {
try {
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': `${process.env.PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ url, format: 'png' })
});
if (!response.ok) {
throw new Error(`Screenshot failed: ${response.status}`);
}
const buffer = await response.arrayBuffer();
return Buffer.from(buffer);
} catch (error) {
console.error('Screenshot error:', error.message);
return null;
}
}
Migration: From Self-Hosted to API
Before:
const screenshot = await page.screenshot({ path: 'out.png' });
After:
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {
'x-api-key': `${process.env.PAGEBOLT_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ url: page.url(), format: 'png' })
});
const screenshot = Buffer.from(await response.arrayBuffer());
Benefits of switching:
- ✅ Faster (50ms vs. 2–5 sec)
- ✅ Lighter (0MB vs. 150–300MB per screenshot)
- ✅ Scales to unlimited concurrent requests
- ✅ Works in serverless, CI, containers without browser installation
- ✅ No complex retry logic needed
Pricing
| Plan | Requests/Month | Cost | Best For |
|---|---|---|---|
| Free | 100 | $0 | Development & testing |
| Starter | 5,000 | $29 | Small projects, side gigs |
| Growth | 25,000 | $79 | Production apps, frequent screenshots |
| Scale | 100,000 | $199 | High-volume automation |
Summary
Playwright is excellent for automation. But screenshots don't have to be expensive.
- ✅ Use Playwright for navigation, interaction, testing
- ✅ Use Screenshot API for visual proof (no browser)
- ✅ One API key, one HTTP request per screenshot
- ✅ No memory overhead, no CI timeout issues
- ✅ Scales from 10 screenshots to 10,000
Drop the browser overhead — free
100 requests/month, no credit card. One API call replaces the browser instance in your Playwright workflow.
Get API key free →