Puppeteer (Chrome headless) based web page renderer.
Renders web pages to HTML, PDF, or screenshots (PNG/JPEG/WebP). Supports both GET and POST requests.
- Node.js >= 24
- Chromium or Docker
docker run -d --name renderer -p 8080:3000 ghcr.io/zenato/puppeteer-renderer:latestpnpm install pnpm devServer runs on port 3000 by default.
docker build . --file ./Dockerfile --tag local/puppeteer-renderer --build-arg SCOPE=puppeteer-renderer docker run -d --name renderer -p 8080:3000 local/puppeteer-rendererThese endpoints support both GET (query parameters) and POST (JSON body).
| Endpoint | Description |
|---|---|
GET/POST /html | Renders page and returns HTML |
GET/POST /screenshot | Captures page screenshot |
GET/POST /pdf | Generates PDF from page |
| Endpoint | Description |
|---|---|
GET /health | Health check. Returns { "status": "ok" } |
The following options apply to /html, /screenshot, and /pdf endpoints.
Note: For complex options like headers, cookies, and nested objects, use POST with JSON body. GET requests support dot notation for simple nested values (e.g., viewport.width=1920).
| Parameter | Type | Default | Description |
|---|---|---|---|
url | string | required | Target URL |
timeout | number | 30000 | Navigation timeout (ms) |
waitUntil | string | 'networkidle2' | When to consider navigation done |
viewport.width | number | 800 | Viewport width |
viewport.height | number | 600 | Viewport height |
device | string | - | Device emulation (e.g., 'iPhone 14 Pro') |
userAgent | string | - | Custom user agent |
headers | object | - | Custom HTTP headers |
cookies | array | - | Cookies to set |
credentials.username | string | - | HTTP basic auth username |
credentials.password | string | - | HTTP basic auth password |
emulateMediaType | string | - | 'screen' or 'print' |
waitForSelector | string | - | Wait for element before capture |
waitForSelectorTimeout | number | 30000 | Selector wait timeout (ms) |
disableCache | boolean | true | Disable page cache |
| Parameter | Type | Default | Description |
|---|---|---|---|
type | string | 'png' | 'png', 'jpeg', or 'webp' |
quality | number | - | Quality (0-100, jpeg/webp only) |
fullPage | boolean | false | Capture full page |
clip | object | - | Clip region { x, y, width, height } |
omitBackground | boolean | false | Transparent background |
encoding | string | 'binary' | 'binary' or 'base64' |
animationTimeout | number | 0 | Wait for animations (ms) |
| Parameter | Type | Default | Description |
|---|---|---|---|
filename | string | - | Custom filename |
contentDisposition | string | 'attachment' | 'attachment' or 'inline' |
scale | number | 1.0 | Scale (0.1 - 2.0) |
format | string | - | Paper format (A4, Letter, etc.) |
landscape | boolean | false | Landscape orientation |
printBackground | boolean | false | Print background graphics |
margin | object | - | Margins { top, right, bottom, left } |
displayHeaderFooter | boolean | false | Show header/footer |
headerTemplate | string | - | Header HTML template |
footerTemplate | string | - | Footer HTML template |
# HTML curl "http://localhost:3000/html?url=https://example.com" # Screenshot with viewport curl "http://localhost:3000/screenshot?url=https://example.com&viewport.width=1920&viewport.height=1080" # PDF curl "http://localhost:3000/pdf?url=https://example.com&filename=report.pdf" -o report.pdf# Screenshot with device emulation curl -X POST http://localhost:3000/screenshot \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "device": "iPhone 14 Pro", "fullPage": true, "type": "webp", "quality": 90 }' -o screenshot.webp # PDF with custom headers and cookies curl -X POST http://localhost:3000/pdf \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/dashboard", "headers": { "Authorization": "Bearer token123" }, "cookies": [{ "name": "session", "value": "abc", "domain": "example.com" }], "printBackground": true, "format": "A4" }' -o dashboard.pdf # Wait for specific element curl -X POST http://localhost:3000/screenshot \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com", "waitForSelector": "#main-content", "waitForSelectorTimeout": 10000 }' -o screenshot.pngAll errors return JSON:
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "URL is required" } }Error codes: VALIDATION_ERROR, NAVIGATION_ERROR, TIMEOUT_ERROR, SELECTOR_NOT_FOUND, BROWSER_ERROR, INTERNAL_ERROR
| Variable | Description |
|---|---|
PORT | Server port (default: 3000) |
IGNORE_HTTPS_ERRORS | Set to 'true' to ignore SSL errors |
PUPPETEER_ARGS | Additional Chromium arguments (separated by --) |
See puppeteer-renderer-middleware for integrating with existing Express apps.
import express from 'express' import renderer from 'puppeteer-renderer-middleware' const app = express() app.use('/render-proxy', renderer({ url: 'http://localhost:3000', })) app.listen(8080)Copyright (c) 2017-present, Yeongjin Lee