How PageBolt achieves 2-5 second screenshot latency (architecture deep dive)
Latency kills. When your screenshot takes 30 seconds, your API times out. When your Vercel edge function runs Puppeteer, you hit the 10-second function timeout. Users bounce. Revenue dies.
PageBolt's screenshot endpoint responds in 2-5 seconds. Here's how.
The Problem: Why Local Chromium Is Slow
Running Chromium locally seems simple:
const browser = await puppeteer.launch();
But this hides massive latency:
- Cold start: 3-8 seconds (launch Chromium, initialize V8, load browser context)
- Page load: 2-5 seconds (network, JavaScript execution, rendering)
- Screenshot capture: 0.5-1 second (DOM traversal, pixel rendering)
- Total: 5.5-14 seconds, and that's best case
On AWS Lambda or Vercel edge functions (10-second timeout), you fail silently. On a busy server, Chromium processes pile up and memory explodes.
The Solution: Distributed Browser Pool
PageBolt doesn't launch Chromium per request. Instead:
- Pre-warmed pools: Chromium instances run constantly in multiple regions (us-east, eu-west, ap-southeast)
- Connection pooling: Each instance handles 50-100 concurrent connections (not sequential requests)
- Intelligent routing: Requests route to the nearest region with available capacity
- Result caching: Screenshots of the same URL are cached for 24 hours
Result: New request comes in → Route to nearest pool → Reuse existing browser context → Screenshot → Cache → Return (2-5 seconds total)
Architecture Diagram
User Request
↓
Global Load Balancer (Route to nearest region)
↓
Regional Browser Pool
├─ Instance 1 (30 active connections)
├─ Instance 2 (25 active connections)
└─ Instance 3 (idle, ready)
↓
Screenshot Cache (Redis)
├─ URL hash → Image (24h TTL)
├─ Redirect if cached → Return (300ms)
└─ Miss → Render new → Cache → Return (3-5s)
Performance Optimization Techniques
1. Pre-warmed Browser Contexts
Instead of launching fresh browsers, we maintain a pool of warm contexts:
// Cold start (Puppeteer)
const browser = await puppeteer.launch(); // 3-8s
const page = await browser.newPage(); // 1-2s
await page.goto(url); // 2-5s
// Total: 6-15s
// Warm pool (PageBolt)
const page = pool.getAvailablePage(); // 50-100ms (from pool)
await page.goto(url); // 2-3s (optimized)
// Total: 2.5-3.5s
2. Aggressive Caching
Most screenshots are of the same URLs repeatedly. We cache aggressively:
const cacheKey = hash(url + options);
const cached = await redis.get(cacheKey);
if (cached) {
return cached; // 300ms from Redis
}
// Cache miss → render → cache → return
Cache hit rate: ~60-70% on production (huge latency win).
3. Network Optimization
Chromium's default network stack is slow. We optimize:
- Block unnecessary resources: Ads, trackers, fonts (save 1-2s)
- Parallel rendering: Execute JavaScript in parallel (save 0.5-1s)
- Viewport scaling: Skip rendering off-screen content (save 0.3-0.5s)
await page.goto(url, {
waitUntil: 'networkidle2', // Wait for network idle, not full load
timeout: 8000 // Fail fast if page is slow
});
Real-World Benchmarks
| Scenario | Puppeteer | PageBolt | Savings |
|---|---|---|---|
| Cold start | 10-15s | 2-3s | 70-80% |
| Warm start (2nd req) | 5-8s | 2-3s | 60-75% |
| Cached result | N/A | 0.3s | Infinite |
| Vercel edge (cold) | ❌ Timeout | ✅ 3-4s | Works |
| Lambda (concurrent) | ❌ OOM | ✅ 2-5s | Works |
Code Example: Measuring Latency
const start = Date.now();
const response = await fetch('https://pagebolt.dev/api/v1/screenshot', {
method: 'POST',
headers: {'x-api-key': YOUR_API_KEY},
body: JSON.stringify({
url: 'https://example.com',
format: 'png'
})
});
const latency = Date.now() - start;
console.log(`Screenshot took ${latency}ms`);
// Output: Screenshot took 2847ms (typical)
Why This Matters
Serverless: Functions with 10-second timeouts now have room for:
- 2-3s screenshot request
- 2-3s additional processing
- Safety margin
Scalability: Pre-warmed pools handle traffic spikes without cold starts.
Cost: One browser instance serving 50+ concurrent requests costs less than 50 on-demand instances.
Reliability: If one region is slow, traffic reroutes instantly.
Trade-offs
PageBolt's architecture sacrifices:
- Custom browser setup (Puppeteer gives more control over browser flags)
- Headful mode (screenshot-only, no interactive browser control)
But gains:
- Massive latency reduction (2-5s vs 10-30s)
- Instant scaling (no cold starts)
- Production-ready (no memory leaks, no zombie processes)
Conclusion
PageBolt's 2-5 second latency comes from three pillars:
- Pre-warmed browser pools (no cold starts)
- Intelligent caching (60-70% hit rate saves 0.3s responses)
- Network optimization (block ads/trackers, parallel rendering)
Result: Screenshot APIs that scale, don't timeout, and cost less to run.
PageBolt is the fastest screenshot API. 2-5 second latency. Free tier: 100 requests/month.
Top comments (0)