Playwright for Serverless
Chromium is ~280MB. Lambda's limit is 250MB. Vercel caps at 50MB. Cloudflare Workers can't run it at all. We solved all of these.
Recognize These?
Chromium is ~280MB. Lambda's unzipped limit is 250MB. The math doesn't work, no matter how clever you get with compression.
Lambda ran out of memory trying to spawn Chrome. You need 512MB minimum, 1-2GB recommended. That gets expensive.
Missing Linux dependencies on Amazon Linux. Time to debug Lambda layers and figure out which .so files are missing.
Cold start + Brotli decompression + Chrome launch + page render exceeded API Gateway's limit. And that's on a fast day.
If you've seen these errors, you know the pain. We built Riddle so you don't have to deal with this anymore.
The Serverless Browser Problem
Every major serverless platform has limits that make headless Chrome difficult or impossible:
AWS Lambda
Chromium is 280MB. @sparticuz/chromium compresses to ~45MB but decompresses to /tmp on every cold start. VPC-enabled Lambdas can take 5+ minutes.
Vercel Functions
Even aggressive compression doesn't work. Developers are stuck pinning ancient Puppeteer versions from 2021. Modern features are out of reach.
Cloudflare Workers
Workers run JavaScript, not containers. You literally cannot run Chrome. Cloudflare's Browser Rendering API exists but is rate-limited to 2/min.
The @sparticuz/chromium Trap
Over 300,000 developers download @sparticuz/chromium every week. Most of them are frustrated within hours.
Version Pinning Hell
Chromium version must match Puppeteer version must match Node.js runtime. AWS updates break your stack. You spend hours debugging compatibility.
Cold Start Penalty
Brotli decompression on every cold start. 5-10 seconds before your function even starts working. In VPCs, this can take minutes.
Memory Instability
Chrome loves RAM. Lambda doesn't have much. Your function crashes randomly on complex pages. "spawn ENOMEM" becomes your new nemesis.
Runtime Update Roulette
April 2024's Node.js 18.20 update froze Puppeteer for thousands of developers. You're one security patch away from a broken production system.
As one developer put it: "We had been burned by using third-party chromium packages and things could easily break with one security patch from AWS."
The Solution: Don't Run Chrome in Lambda
Instead of fighting Lambda limits, call an API. We run Playwright in proper infrastructure so you don't have to.
Your Lambda calls Riddle
POST a URL or a Playwright script. We handle the browser.
We run Chrome properly
No size limits, no memory constraints, no cold start decompression. Just Chrome running on real infrastructure.
You get your screenshot
PNG delivered to S3. Poll for completion or use webhooks. Download when ready.
Before and After
Before: Lambda with @sparticuz/chromium (50+ lines of config)
// serverless.yml - just the chromium layer config
layers:
chromium:
path: layer
compatibleRuntimes:
- nodejs18.x
package:
artifact: layer/chromium.zip
// handler.js - and pray it works
const chromium = require("@sparticuz/chromium");
const puppeteer = require("puppeteer-core");
exports.handler = async (event) => {
// Configure for Lambda's weird environment
chromium.setHeadlessMode = true;
chromium.setGraphicsMode = false;
const browser = await puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath(),
headless: chromium.headless,
});
// Hope Chrome doesn't crash...
const page = await browser.newPage();
await page.goto(event.url);
const screenshot = await page.screenshot();
await browser.close();
return screenshot;
};After: One API call
// That's it. No layers, no binaries, no config.
const response = await fetch("https://api.riddledc.com/v1/run", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({ url: "https://example.com" })
});
const { job_id } = await response.json();
// Poll for completion, get your screenshotFull Comparison
| Factor | Self-Hosted Lambda | Riddle API |
|---|---|---|
| Setup time | Hours of debugging layers, binaries, dependencies | curl command in 2 minutes |
| Size limit | 250MB (Chromium is 280MB) | Not your problem |
| Memory needed | 1-2GB minimum, crashes common | Whatever your Lambda actually needs |
| Cold start | 5-10s (Brotli decompression) | ~2s (HTTP call) |
| Maintenance | Breaks with Node.js runtime updates | We handle it |
| Version compatibility | Chromium + Puppeteer + Node.js matrix | Always latest |
| Works on Vercel | Barely (ancient versions only) | Yes |
| Works on Cloudflare | No | Yes |
| Cost per job | ~$0.001 + compute + your debugging time | from $0.004 (all-in) |
What You Can Do
Simple Screenshots
POST a URL, get a PNG. Pass auth headers to screenshot staging environments and protected pages.
JSON Workflows
Multi-page flows, form fills, clicks, waits. Send JSON steps, no code required.
Batch Screenshots
Take multiple screenshots in one job. Get below $0.001 per screenshot with batching.
PDF Generation
Render pages to PDF with full CSS support. No more wkhtmltopdf headaches.
Simple Pricing
30-second minimum
With batching (multiple per job)
No subscriptions. No monthly minimums. No "units" to figure out. Just pay for browser time.
See how to maximize value → | Screenshot authenticated pages →
Stop Fighting Lambda
Create an account and get screenshots in minutes, not hours.