---
url: /chromium-pdf-service/api/endpoints.md
---
# API Endpoints
::: tip Interactive API Documentation
Swagger UI is available at `/docs` in development mode. You can explore and test all endpoints interactively.
:::
## PDF Generation
### Generate PDF from HTML
```bash
POST /api/pdf/from-html
Content-Type: application/json
```
```json
{
"requestedKey": "invoice-12345",
"html": "
Hello World
",
"options": {
"pdf": {
"format": "A4",
"printBackground": true
}
}
}
```
### Generate PDF from URL
```bash
POST /api/pdf/from-url
Content-Type: application/json
```
```json
{
"requestedKey": "website-snapshot",
"url": "https://example.com",
"options": {
"browser": {
"timeout": 30000,
"viewport": { "width": 1920, "height": 1080 }
}
}
}
```
### Generate PDF with Custom Dimensions
```json
{
"requestedKey": "custom-size-pdf",
"url": "https://example.com",
"options": {
"browser": {
"viewport": { "width": 400, "height": 800 }
},
"pdf": {
"width": 400,
"height": 800,
"printBackground": true
}
}
}
```
### Generate PDF with Loading Rules
```json
{
"requestedKey": "spa-page",
"url": "https://example.com/dashboard",
"options": {
"browser": {
"timeout": 60000,
"waitForSelector": "#chart-container",
"waitAfter": 2000
},
"pdf": {
"format": "A4",
"printBackground": true
}
}
}
```
::: tip
This waits for the `#chart-container` element to appear, then waits an additional 2 seconds before generating the PDF.
:::
### Generate PDF with Animations Disabled
```json
{
"requestedKey": "no-animation-pdf",
"url": "https://example.com/animated-page",
"options": {
"browser": {
"disableAnimations": true
},
"pdf": {
"format": "A4",
"printBackground": true
}
}
}
```
::: tip Why disable animations?
CSS animations and transitions can cause elements to be captured mid-animation, resulting in invisible, partially visible, or incorrectly positioned elements in the PDF. This option injects CSS to disable all animations and sets `prefers-reduced-motion: reduce` for reliable rendering.
:::
### Generate PDF with Custom Headers
```json
{
"requestedKey": "auth-page",
"url": "https://example.com/protected",
"options": {
"browser": {
"userAgent": "Mozilla/5.0 Custom Agent",
"extraHTTPHeaders": {
"Authorization": "Bearer your-token",
"X-Custom-Header": "custom-value"
}
}
}
}
```
### Generate PDF from File
```bash
POST /api/pdf/from-file
Content-Type: multipart/form-data
file:
requestedKey: report-001
options: {"pdf": {"format": "Letter"}}
```
## Screenshot Generation
### Generate Screenshot from HTML
```bash
POST /api/screenshot/from-html
Content-Type: application/json
```
```json
{
"requestedKey": "page-capture-001",
"html": "Hello World
",
"options": {
"screenshot": {
"type": "png",
"fullPage": true
}
}
}
```
### Generate Screenshot from URL
```bash
POST /api/screenshot/from-url
Content-Type: application/json
```
```json
{
"requestedKey": "website-screenshot",
"url": "https://example.com",
"options": {
"browser": {
"viewport": { "width": 1920, "height": 1080 }
},
"screenshot": {
"type": "png",
"fullPage": true
}
}
}
```
### Generate JPEG Screenshot with Quality
```json
{
"requestedKey": "compressed-screenshot",
"url": "https://example.com",
"options": {
"screenshot": {
"type": "jpeg",
"quality": 80,
"fullPage": true
}
}
}
```
### Capture Specific Region
```json
{
"requestedKey": "region-capture",
"url": "https://example.com",
"options": {
"screenshot": {
"type": "png",
"fullPage": false,
"clip": {
"x": 0,
"y": 0,
"width": 800,
"height": 600
}
}
}
}
```
::: tip
Use `clip` to capture a specific region of the page. When using `clip`, set `fullPage` to `false`.
:::
### Transparent Background (PNG only)
```json
{
"requestedKey": "transparent-screenshot",
"html": "Hello
",
"options": {
"screenshot": {
"type": "png",
"omitBackground": true
}
}
}
```
### Generate Screenshot from File
```bash
POST /api/screenshot/from-file
Content-Type: multipart/form-data
file:
requestedKey: screenshot-001
options: {"screenshot": {"type": "png", "fullPage": true}}
```
### Get Screenshot Job Status
```bash
GET /api/screenshot/status/:requestedKey
```
### Cancel/Remove Screenshot Job
```bash
DELETE /api/screenshot/:requestedKey
```
### Download Screenshot
```bash
GET /api/screenshot/download/:requestedKey
```
Downloads the generated screenshot file. Returns the image with appropriate Content-Type (`image/png` or `image/jpeg`).
**Response Headers:**
* `Content-Type`: `image/png` or `image/jpeg`
* `Content-Disposition`: `attachment; filename=""`
* `Content-Length`: File size in bytes
**Error Responses:**
* `404` - Job not found or file not found
* `409` - Screenshot not ready (still processing or failed)
## Job Management
### Get Job Status
```bash
GET /api/pdf/status/:requestedKey
```
Response:
```json
{
"requestedKey": "invoice-12345",
"status": "completed",
"progress": 100,
"createdAt": "2025-01-15T10:30:00.000Z",
"updatedAt": "2025-01-15T10:30:05.000Z",
"filePath": "pdf-files/15-01-2025/invoice-12345__15-01-2025_10-30-05.pdf"
}
```
### Cancel Job
```bash
DELETE /api/pdf/cancel/:requestedKey
```
### Download PDF
```bash
GET /api/pdf/download/:requestedKey
```
### Queue Statistics
```bash
GET /api/pdf/queue
```
## Health Checks
```bash
GET /health # Basic health check
GET /health/ready # Readiness probe
GET /health/live # Liveness probe with queue stats
```
## Settings
### Get Current Settings
```bash
GET /api/settings
```
### Update Settings
```bash
PUT /api/settings
Content-Type: application/json
```
```json
{
"browser": {
"maxConcurrent": 5
},
"queue": {
"maxSize": 200
}
}
```
### Reset to Defaults
```bash
POST /api/settings/reset
```
---
---
url: /chromium-pdf-service/api/browser-options.md
---
# Browser Options
Browser options control how the page is loaded and rendered.
## Options Reference
| Option | Type | Description |
|--------|------|-------------|
| `timeout` | number | Navigation timeout in ms (max 120000) |
| `viewport` | object | `{ width, height }` |
| `userAgent` | string | Custom user agent |
| `extraHTTPHeaders` | object | Additional HTTP headers |
| `waitForSelector` | string | CSS selector to wait for before generating PDF |
| `waitAfter` | number | Additional wait time (ms) after page load or selector appears (max 60000) |
| `disableAnimations` | boolean | Disable all CSS animations and transitions |
| `colorScheme` | string | Emulate preferred color scheme: `"light"`, `"dark"`, or `"no-preference"` |
| `launchOptions` | object | Custom browser launch options `{ headless, args }` |
## Examples
### Custom Viewport
```json
{
"options": {
"browser": {
"viewport": {
"width": 1920,
"height": 1080
}
}
}
}
```
### Custom User Agent
```json
{
"options": {
"browser": {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
}
}
```
### Custom Headers
```json
{
"options": {
"browser": {
"extraHTTPHeaders": {
"Authorization": "Bearer your-token",
"Accept-Language": "en-US"
}
}
}
}
```
### Wait for Element
```json
{
"options": {
"browser": {
"waitForSelector": "#content-loaded",
"waitAfter": 1000
}
}
}
```
### Disable Animations
```json
{
"options": {
"browser": {
"disableAnimations": true
}
}
}
```
::: tip
Use `disableAnimations: true` when your page has CSS animations that might cause elements to be invisible or transformed when the PDF is captured.
:::
### Dark Mode
```json
{
"options": {
"browser": {
"colorScheme": "dark"
}
}
}
```
### Light Mode
```json
{
"options": {
"browser": {
"colorScheme": "light"
}
}
}
```
::: tip
The `colorScheme` option emulates the `prefers-color-scheme` CSS media feature. Use `"dark"` to render pages in dark mode, `"light"` for light mode, or `"no-preference"` to use the system default. This is useful for websites that support both light and dark themes.
:::
## Launch Options
The `launchOptions` parameter allows you to customize how the Chromium browser is launched. When provided, a dedicated browser instance is created for that specific job.
### Available Launch Options
| Option | Type | Description |
|--------|------|-------------|
| `headless` | boolean | Run browser in headless mode (default: `true`) |
| `args` | string\[] | Array of Chromium command-line arguments (max 50 args, each max 500 chars) |
### Non-Headless Mode (Debugging)
Run the browser with a visible UI for debugging:
```json
{
"options": {
"browser": {
"launchOptions": {
"headless": false
}
}
}
}
```
::: warning
Non-headless mode is useful for debugging but not recommended for production use. The browser window will be visible on the server, which may cause issues in containerized or headless environments.
:::
### Common Chromium Arguments
```json
{
"options": {
"browser": {
"launchOptions": {
"args": [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-gpu",
"--window-size=1920,1080"
]
}
}
}
}
```
**Useful Arguments:**
* `--no-sandbox` - Disable sandbox (required in some Docker environments)
* `--disable-setuid-sandbox` - Disable setuid sandbox
* `--disable-gpu` - Disable GPU hardware acceleration
* `--window-size=WIDTH,HEIGHT` - Set initial window size
* `--disable-dev-shm-usage` - Avoid /dev/shm usage issues in containers
* `--disable-web-security` - Disable CORS (development only!)
* `--disable-font-subpixel-positioning` - Improve font rendering consistency
* `--single-process` - Run browser in single process mode (debugging only)
::: danger Security Warning
Some arguments like `--no-sandbox` and `--disable-web-security` reduce browser security. Only use these in development or when absolutely necessary in trusted environments.
:::
### Performance Considerations
When you provide custom `launchOptions`:
* A **dedicated browser instance** is created for that specific job
* The browser is **automatically closed** after the job completes
* This adds overhead compared to using the shared browser instance
* Use only when necessary (debugging, special requirements)
Without custom `launchOptions`, jobs use the shared browser instance configured in global settings, which is more efficient for most use cases.
### Example: Docker-Optimized Launch
```json
{
"requestedKey": "docker-pdf",
"url": "https://example.com",
"options": {
"browser": {
"launchOptions": {
"args": [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage",
"--disable-gpu"
]
}
}
}
}
```
### Example: Debug with Visible Browser
```json
{
"requestedKey": "debug-pdf",
"html": "Test Page
",
"options": {
"browser": {
"launchOptions": {
"headless": false,
"args": [
"--window-size=1920,1080",
"--start-maximized"
]
},
"waitAfter": 3000
}
}
}
```
::: tip Debugging Workflow
1. Start with `headless: false` to visually inspect the page
2. Add `waitAfter` to give yourself time to see the rendered page
3. Once satisfied, remove `launchOptions` or set `headless: true` for production
:::
---
---
url: /chromium-pdf-service/development.md
---
# Development Guide
This guide covers setting up and developing the Chromium PDF Service locally.
## Prerequisites
* Node.js >= 24.0.0
* npm or yarn
* Docker (optional, for containerized development)
## Local Setup
### 1. Clone and Install
```bash
git clone https://github.com/chromium-pdf/chromium-pdf-service.git
cd chromium-pdf-service
# Install dependencies
npm install
# Install Playwright browsers
npx playwright install chromium
```
### 2. Environment Setup
```bash
# Copy example environment file
cp .env.example .env
```
### 3. Run Development Server
```bash
npm run dev
```
The service starts at `http://localhost:3000` with hot-reload enabled.
## Available Scripts
| Command | Description |
|---------|-------------|
| `npm run dev` | Start development server with hot-reload |
| `npm run build` | Compile TypeScript to JavaScript |
| `npm start` | Run production build |
| `npm run lint` | Run ESLint |
| `npm run lint:fix` | Fix ESLint issues automatically |
| `npm run format` | Format code with Prettier |
| `npm run format:check` | Check code formatting |
| `npm run typecheck` | Run TypeScript type checking |
| `npm test` | Run tests once |
| `npm run test:watch` | Run tests in watch mode |
| `npm run test:ui` | Open Vitest UI |
| `npm run test:coverage` | Run tests with coverage report |
| `npm run docs:dev` | Start documentation dev server |
| `npm run docs:build` | Build documentation |
## Project Structure
```
chromium-pdf-service/
├── src/
│ ├── index.ts # Entry point
│ ├── app.ts # Fastify app setup
│ ├── config/
│ │ ├── env.ts # Environment variables
│ │ └── default-settings.ts
│ ├── routes/
│ │ ├── pdf.routes.ts # PDF generation endpoints
│ │ ├── screenshot.routes.ts # Screenshot endpoints
│ │ ├── status.routes.ts # Job status endpoints
│ │ ├── health.routes.ts # Health check endpoints
│ │ └── settings.routes.ts
│ ├── services/
│ │ ├── pdf-generator.ts # Core PDF generation
│ │ ├── screenshot-generator.ts # Screenshot generation
│ │ ├── queue-manager.ts # Job queue management
│ │ └── settings-manager.ts
│ ├── middleware/
│ │ ├── error-handler.ts
│ │ └── auth.ts # API key authentication
│ ├── schemas/ # Zod validation schemas
│ ├── types/ # TypeScript types
│ └── utils/
│ ├── logger.ts
│ ├── filename.ts
│ ├── url-validator.ts
│ └── html-sanitizer.ts
├── tests/ # Test files
├── docs/ # VitePress documentation
├── data/ # Runtime data (settings, queue)
├── pdf-files/ # Generated PDFs/screenshots
└── logs/ # Log files
```
## Testing
### Run All Tests
```bash
npm test
```
### Run Tests in Watch Mode
```bash
npm run test:watch
```
### Run Tests with UI
```bash
npm run test:ui
```
### Run Tests with Coverage
```bash
npm run test:coverage
```
### Test Structure
```txt
tests/
├── routes/ # Route/endpoint tests
├── services/ # Service layer tests
├── middleware/ # Middleware tests
├── schemas/ # Schema validation tests
└── utils/ # Utility function tests
```
## Code Quality
### Linting
```bash
# Check for issues
npm run lint
# Auto-fix issues
npm run lint:fix
```
### Formatting
```bash
# Format all files
npm run format
# Check formatting
npm run format:check
```
### Type Checking
```bash
npm run typecheck
```
## API Documentation
Swagger UI is available in development mode:
```txt
http://localhost:3000/docs
```
## Debugging
### Enable Debug Logging
```bash
LOG_LEVEL=debug npm run dev
```
### View Logs
Logs are written to:
* Console (pretty-printed in development)
* `logs/` directory (JSON format)
### Using launchOptions for Browser Debugging
When debugging PDF or screenshot generation issues, you can pass custom browser `launchOptions` per request to see what's happening in the browser. This is especially useful for:
**Visual Debugging with Non-Headless Mode:**
Running the browser in non-headless mode lets you see exactly what the page looks like before PDF/screenshot generation:
```bash
curl -X POST http://localhost:3000/api/pdf/from-url \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "debug-test",
"url": "https://example.com",
"options": {
"browser": {
"launchOptions": {
"headless": false
}
}
}
}'
```
**Common Debugging Scenarios:**
1. **Layout Issues**: Use `headless: false` to visually inspect page rendering before PDF generation
2. **Font Problems**: Add `--disable-font-subpixel-positioning` to args for consistent font rendering
3. **Security Errors**: Use `--no-sandbox` and `--disable-setuid-sandbox` in containerized environments
4. **Network Issues**: Add `--disable-web-security` (development only!) to bypass CORS restrictions
5. **Performance Testing**: Use `--single-process` to simplify debugging
**Example with Multiple Debug Args:**
```json
{
"requestedKey": "debug-complex",
"html": "Test Page
",
"options": {
"browser": {
"launchOptions": {
"headless": false,
"args": [
"--window-size=1920,1080",
"--disable-gpu",
"--no-sandbox",
"--disable-setuid-sandbox"
]
},
"waitAfter": 2000
}
}
}
```
**Important Notes:**
* Custom `launchOptions` create a dedicated browser instance for that job
* The browser is automatically closed after job completion
* Without custom `launchOptions`, jobs use the shared browser instance
* Non-headless mode is not recommended for production use
* Some args like `--no-sandbox` reduce security and should only be used in development
## Making Changes
### Adding a New Route
1. Create route file in `src/routes/`
2. Define Zod schemas in `src/schemas/`
3. Register route in `src/app.ts`
4. Add tests in `tests/routes/`
### Adding a New Service
1. Create service file in `src/services/`
2. Export singleton instance
3. Add tests in `tests/services/`
### Adding Environment Variables
1. Add to `src/config/env.ts`
2. Update `.env.example`
3. Update `docs/config/env-variables.md`
---
---
url: /chromium-pdf-service/development/docker-build.md
---
# Docker Build & Test
This guide covers building and testing the Docker image locally.
## Building the Image
### Basic Build
```bash
docker build -t chromium-pdf-service:latest .
```
### Build with Version Tag
```bash
# With specific version
docker build -t chromium-pdf-service:1.0.0 .
# With multiple tags
docker build -t chromium-pdf-service:latest -t chromium-pdf-service:1.0.0 .
```
### Build with No Cache
```bash
docker build --no-cache -t chromium-pdf-service:latest .
```
### Build with Build Arguments
```bash
docker build \
--build-arg NODE_ENV=production \
-t chromium-pdf-service:latest .
```
## Running the Container
### Basic Run
```bash
docker run -d -p 3000:3000 chromium-pdf-service:latest
```
### Run with Environment Variables
```bash
docker run -d \
-p 3000:3000 \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-e RATE_LIMIT_MAX=100 \
-e API_KEYS=my-secret-key \
chromium-pdf-service:latest
```
### Run with Volume Mounts
```bash
docker run -d \
-p 3000:3000 \
-v $(pwd)/data:/app/data \
-v $(pwd)/pdf-files:/app/pdf-files \
-v $(pwd)/logs:/app/logs \
chromium-pdf-service:latest
```
### Run with All Options
```bash
docker run -d \
--name pdf-service \
-p 3000:3000 \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-e RATE_LIMIT_MAX=50 \
-e API_KEYS=key1,key2 \
-e BLOCK_PRIVATE_IPS=true \
-v $(pwd)/data:/app/data \
-v $(pwd)/pdf-files:/app/pdf-files \
-v $(pwd)/logs:/app/logs \
--restart unless-stopped \
chromium-pdf-service:latest
```
## Testing the Container
### 1. Check Container Status
```bash
# List running containers
docker ps
# Check container logs
docker logs pdf-service
# Follow logs in real-time
docker logs -f pdf-service
```
### 2. Test Health Endpoints
```bash
# Health check
curl http://localhost:3000/health
# Readiness probe
curl http://localhost:3000/health/ready
# Liveness probe
curl http://localhost:3000/health/live
```
Expected response:
```json
{"status":"healthy","timestamp":"2025-01-01T00:00:00.000Z"}
```
### 3. Test PDF Generation
```bash
# Generate PDF from HTML
curl -X POST http://localhost:3000/api/pdf/html \
-H "Content-Type: application/json" \
-H "X-API-Key: my-secret-key" \
-d '{
"requestedKey": "test-001",
"html": "Hello World
Test PDF
"
}'
# Check job status
curl http://localhost:3000/api/pdf/status/test-001 \
-H "X-API-Key: my-secret-key"
# Download PDF (when completed)
curl -O http://localhost:3000/api/pdf/download/test-001 \
-H "X-API-Key: my-secret-key"
```
### 4. Test URL to PDF
```bash
curl -X POST http://localhost:3000/api/pdf/url \
-H "Content-Type: application/json" \
-H "X-API-Key: my-secret-key" \
-d '{
"requestedKey": "example-page",
"url": "https://example.com"
}'
```
## Docker Compose
### Development
```bash
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
```
### Production
```bash
# Build and start
docker-compose -f docker-compose.yml up -d --build
# Scale (if needed)
docker-compose up -d --scale pdf-service=2
```
## Troubleshooting
### Container Won't Start
```bash
# Check logs for errors
docker logs pdf-service
# Check if port is in use
lsof -i :3000
# Run interactively for debugging
docker run -it --rm chromium-pdf-service:latest /bin/bash
```
### PDF Generation Fails
```bash
# Check Chromium is working
docker exec -it pdf-service npx playwright install --dry-run
# Check available memory
docker stats pdf-service
# Increase memory limit
docker run -d --memory=2g chromium-pdf-service:latest
```
### Permission Issues
```bash
# Check volume permissions
ls -la ./pdf-files
# Fix permissions
chmod 777 ./pdf-files ./data ./logs
```
### Browser Crashes
Add these flags if browser crashes:
```bash
docker run -d \
--shm-size=2gb \
-p 3000:3000 \
chromium-pdf-service:latest
```
## Performance Tips
### 1. Use Multi-Stage Build
The Dockerfile already uses multi-stage builds to minimize image size.
### 2. Set Resource Limits
```bash
docker run -d \
--memory=2g \
--cpus=2 \
-p 3000:3000 \
chromium-pdf-service:latest
```
### 3. Use Health Checks
```bash
docker run -d \
--health-cmd="curl -f http://localhost:3000/health || exit 1" \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
-p 3000:3000 \
chromium-pdf-service:latest
```
### 4. Optimize for Production
```yaml
# docker-compose.prod.yml
services:
pdf-service:
image: chromium-pdf-service:latest
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
```
## CI/CD Integration
### Automated Publishing
This project uses GitHub Actions to automatically build and publish Docker images to GitHub Container Registry (ghcr.io).
**Workflow:**
1. Push a version tag (e.g., `git tag v1.0.0 && git push --tags`)
2. Tests workflow runs automatically
3. On test success, Docker image is built for `linux/amd64` and `linux/arm64`
4. Image is pushed to `ghcr.io/chromium-pdf/chromium-pdf-service`
**Versioning:**
| Git Tag | Docker Tags |
|---------|-------------|
| `v1.2.3` | `1.2.3`, `1.2`, `1`, `latest` |
| `v0.0.2-alpha` | `0.0.2-alpha` |
### Manual Trigger
You can also manually trigger a build from GitHub Actions:
1. Go to Actions → "🐳 Publish Docker Image"
2. Click "Run workflow"
3. Optionally specify a custom tag
### Local CI Testing
```yaml
# Test locally before pushing
- name: Build Docker image
run: docker build -t chromium-pdf-service:${{ github.sha }} .
- name: Test Docker image
run: |
docker run -d -p 3000:3000 --name test chromium-pdf-service:${{ github.sha }}
sleep 5
curl -f http://localhost:3000/health
docker stop test
```
### Creating a Release
```bash
# Create and push a version tag
git tag v1.0.0
git push origin v1.0.0
# The workflow will automatically:
# 1. Run all tests
# 2. Build multi-platform image
# 3. Push to ghcr.io/chromium-pdf/chromium-pdf-service:1.0.0
```
---
---
url: /chromium-pdf-service/guide/docker-networking.md
---
# Docker Networking
When running the PDF service in Docker, you may need to access URLs on your host machine or local network. This guide covers common networking scenarios.
## Access Host Machine from Container
Use `host.docker.internal` to access services on your host:
```json
{
"requestedKey": "local-page",
"url": "http://host.docker.internal:8080/my-page"
}
```
::: tip
`host.docker.internal` works on **macOS** and **Windows**. For Linux, see the [Linux Host Access](#linux-host-access) section.
:::
## Access Other Containers
When containers are on the same network, use service names:
```json
{
"requestedKey": "other-service",
"url": "http://my-web-app:3000/page-to-print"
}
```
## URL Reference
| From | URL Pattern |
|------|-------------|
| Host machine | `http://localhost:4500/...` |
| Inside Docker (same network) | `http://pdf-service:3000/...` |
| PDF service → host | `http://host.docker.internal:PORT/...` |
| PDF service → other container | `http://service-name:PORT/...` |
## Setting Up a Shared Network
1. Create a shared network:
```bash
docker network create my-network
```
1. Connect both containers to it:
```yaml
# docker-compose.yml for PDF service
services:
pdf-service:
# ...
networks:
- my-network
networks:
my-network:
external: true
```
```yaml
# docker-compose.yml for your web app
services:
my-web-app:
# ...
networks:
- my-network
networks:
my-network:
external: true
```
## Local Domain Names (.test, .local, .dev)
If you use local domain names like `myapp.test` or `localhost.test` configured via `/etc/hosts` or local DNS (dnsmasq, etc.), the Docker container cannot resolve them by default.
### Solution 1: Use host.docker.internal (Recommended)
Replace your local domain with `host.docker.internal`:
```bash
# Instead of
http://myapp.test:3000
# Use
http://host.docker.internal:3000
```
### Solution 2: Add extra\_hosts in Docker Compose
Map your local domain to the host gateway:
```yaml
services:
chromium-pdf-service:
image: chromium-pdf/chromium-pdf-service:latest
extra_hosts:
- "myapp.test:host-gateway"
- "localhost.test:host-gateway"
```
### Solution 3: Use Your Machine's IP Address
Find your local IP and use it directly:
```bash
# macOS/Linux
ifconfig | grep "inet " | grep -v 127.0.0.1
# Windows
ipconfig | findstr /i "IPv4"
```
Then use the IP in your requests:
```json
{
"requestedKey": "local-page",
"url": "http://192.168.1.100:3000/my-page"
}
```
### Solution 4: Custom DNS Configuration
If you have a local DNS server, configure Docker to use it:
```yaml
services:
chromium-pdf-service:
image: chromium-pdf/chromium-pdf-service:latest
dns:
- 192.168.1.1 # Your router/DNS server
extra_hosts:
- "myapp.test:host-gateway"
```
## Linux Host Access
On Linux, `host.docker.internal` may not work by default. Use one of these approaches:
### Option 1: Add host-gateway (Docker 20.10+)
```yaml
services:
chromium-pdf-service:
extra_hosts:
- "host.docker.internal:host-gateway"
```
### Option 2: Use --network host
```bash
docker run --network host chromium-pdf/chromium-pdf-service:latest
```
::: warning
Using `--network host` disables network isolation. The container shares the host's network stack.
:::
### Option 3: Use Host IP Directly
```bash
# Get your host IP
hostname -I | awk '{print $1}'
# Use in requests
http://172.17.0.1:8080/my-page # Default Docker bridge gateway
```
## Playground Configuration
When using the [Playground](/development/playground) with a containerized PDF service:
1. **Service running in Docker, Playground on host:**
* Set Server URL to `http://localhost:4500` (mapped port)
2. **Both running in Docker:**
* Use container service name: `http://chromium-pdf-service:3000`
3. **Playground accessing local development sites:**
* Use `host.docker.internal` instead of `localhost`
* Or add `extra_hosts` mapping for your local domains
### Example: Local Development Setup
```yaml
# docker-compose.yml
services:
chromium-pdf-service:
image: chromium-pdf/chromium-pdf-service:latest
ports:
- "4500:3000"
extra_hosts:
- "host.docker.internal:host-gateway"
- "myapp.test:host-gateway"
- "api.local:host-gateway"
```
## Framework Dev Server Configuration
Many frontend frameworks block requests from unknown hosts by default. You need to configure them to allow `host.docker.internal`.
### Angular
Add `host.docker.internal` to `allowedHosts` in `angular.json`:
```json
{
"projects": {
"your-app": {
"architect": {
"serve": {
"options": {
"allowedHosts": [
"localhost",
"host.docker.internal"
]
}
}
}
}
}
}
```
Or use the CLI flag:
```bash
ng serve --host 0.0.0.0 --allowed-hosts host.docker.internal
```
Or allow all hosts (development only):
```bash
ng serve --host 0.0.0.0 --disable-host-check
```
### Next.js
In `next.config.js`:
```js
module.exports = {
allowedDevHosts: ['host.docker.internal'],
}
```
### Vite (Vue, React, Svelte)
In `vite.config.js`:
```js
export default {
server: {
host: '0.0.0.0',
allowedHosts: ['host.docker.internal'],
},
}
```
### Webpack Dev Server
In `webpack.config.js`:
```js
module.exports = {
devServer: {
host: '0.0.0.0',
allowedHosts: ['host.docker.internal'],
},
}
```
::: warning Security Note
Only allow specific hosts in production. Using `--disable-host-check` or allowing all hosts should be limited to local development.
:::
## Troubleshooting
### Container can't resolve hostname
```bash
# Test DNS resolution inside container
docker exec -it nslookup myapp.test
# If it fails, use extra_hosts or direct IP
```
### Connection refused
1. Ensure the target service is running
2. Check if the port is exposed
3. Verify firewall settings allow Docker connections
### Timeout errors
1. Check if the URL is accessible from host first
2. Verify network connectivity between containers
3. Increase timeout in browser options:
```json
{
"options": {
"browser": {
"timeout": 60000
}
}
}
```
---
---
url: /chromium-pdf-service/guide/docker.md
---
# Docker Setup
## Quick Start with Pre-built Image
The easiest way to get started is using the pre-built image from GitHub Container Registry:
```bash
# Pull the latest image
docker pull ghcr.io/chromium-pdf/chromium-pdf-service:latest
# Or pull a specific version
docker pull ghcr.io/chromium-pdf/chromium-pdf-service:0.0.2-alpha
```
### Run the Container
```bash
docker run -d \
--name pdf-service \
-p 3000:3000 \
-v $(pwd)/pdf-files:/app/pdf-files \
ghcr.io/chromium-pdf/chromium-pdf-service:latest
```
### Available Tags
| Tag | Description |
|-----|-------------|
| `latest` | Latest stable release |
| `x.y.z` | Specific version (e.g., `0.0.2-alpha`) |
| `x.y` | Latest patch of minor version |
| `x` | Latest minor of major version |
## Using Docker Compose
### With Pre-built Image
```yaml
services:
pdf-service:
image: ghcr.io/chromium-pdf/chromium-pdf-service:latest
ports:
- "3000:3000"
volumes:
- ./pdf-files:/app/pdf-files
- ./data:/app/data
- ./logs:/app/logs
environment:
- NODE_ENV=production
```
### Build Locally
```bash
# Build and start the service
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the service
docker-compose down
```
## Using in Another Docker Compose Project
Add the service to your project's `docker-compose.yml`:
```yaml
services:
your-app:
# your app config...
depends_on:
- pdf-service
pdf-service:
image: ghcr.io/chromium-pdf/chromium-pdf-service:latest
ports:
- "4500:3000"
volumes:
- ./pdf-files:/app/pdf-files
- ./data:/app/data
- ./logs:/app/logs
environment:
- NODE_ENV=production
restart: unless-stopped
```
Access from your app container:
```txt
http://pdf-service:3000/api/pdf/from-url
http://pdf-service:3000/api/screenshot/from-url
```
Access from host machine:
```txt
http://localhost:4500/api/pdf/from-url
http://localhost:4500/api/screenshot/from-url
```
## Environment Variables
Configure the service with environment variables:
```yaml
services:
pdf-service:
image: ghcr.io/chromium-pdf/chromium-pdf-service:latest
environment:
- NODE_ENV=production
- LOG_LEVEL=info
- RATE_LIMIT_MAX=100
- API_KEYS=your-secret-key
- BLOCK_PRIVATE_IPS=true
```
See [Environment Variables](/config/env-variables) for all options.
## Multi-Platform Support
The pre-built images support both `linux/amd64` and `linux/arm64` architectures, making them compatible with:
* Standard x86\_64 servers
* Apple Silicon Macs (M1/M2/M3)
* ARM-based cloud instances (AWS Graviton, etc.)
---
---
url: /chromium-pdf-service/config/env-variables.md
---
# Environment Variables
Configure the service using environment variables.
## Server Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `HOST` | `0.0.0.0` | Server host |
| `PORT` | `3000` | Server port |
| `NODE_ENV` | `development` | Environment mode |
| `LOG_LEVEL` | `info` | Logging level |
| `SETTINGS_PATH` | `data/settings.json` | Settings file path |
| `OUTPUT_DIR` | `pdf-files` | PDF output directory |
| `LOGS_DIR` | `logs` | Process logs directory |
## Security Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `RATE_LIMIT_MAX` | `100` | Max requests per time window |
| `RATE_LIMIT_WINDOW` | `60000` | Time window in ms (1 minute) |
| `API_KEYS` | *(empty)* | Comma-separated API keys for authentication |
| `ALLOWED_ORIGINS` | *(empty)* | Comma-separated CORS origins |
| `ALLOWED_URL_DOMAINS` | *(empty)* | Comma-separated allowed URL domains |
| `BLOCK_PRIVATE_IPS` | `true` | Block private IP addresses in URLs |
| `SANITIZE_HTML` | `false` | Enable HTML sanitization |
::: tip
See the [Security Guide](/guide/security) for detailed configuration options.
:::
## Usage
### Local Development
```bash
PORT=4000 LOG_LEVEL=debug npm run dev
```
### Docker Compose
```yaml
services:
pdf-service:
image: chromium-pdf-service:latest
environment:
- NODE_ENV=production
- PORT=3000
- LOG_LEVEL=info
- OUTPUT_DIR=/app/pdf-files
- LOGS_DIR=/app/logs
```
### Docker Run
```bash
docker run -d \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-p 4500:3000 \
chromium-pdf-service:latest
```
## Log Levels
| Level | Description |
|-------|-------------|
| `trace` | Very detailed debugging |
| `debug` | Debugging information |
| `info` | General information (default) |
| `warn` | Warning messages |
| `error` | Error messages only |
| `fatal` | Fatal errors only |
---
---
url: /chromium-pdf-service/api/examples.md
---
# Example Requests
This page provides complete, ready-to-use examples for common PDF generation scenarios.
## 1. Simple Invoice PDF
Generate a basic invoice from HTML content.
```bash
curl -X POST http://localhost:3000/api/pdf/from-html \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "invoice-2025-001",
"html": "| Web Development Services | $2,500.00 |
| Hosting (Annual) | $300.00 |
Total: $2,800.00
",
"options": {
"pdf": {
"format": "A4",
"printBackground": true,
"margin": { "top": "20mm", "bottom": "20mm", "left": "20mm", "right": "20mm" }
}
}
}'
```
## 1.1 Simple Invoice PDF with custom dimensions
Generate a basic invoice from URL and custom dimensions.
```bash
curl -X POST http://localhost:3000/api/pdf/from-url \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "e818261b-ddf0-44b6-ac98-39becdac8fe2",
"url": "https://example.com/payment/summary?transactionKey=e818261b-ddf0-44b6-ac98-39becdac8fe2&pdfView=true",
"reCreate": true,
"options": {
"pdf": {
"printBackground": true,
"landscape": false,
"width": 800,
"height": 1300,
"margin": {
"top": "0mm",
"right": "0mm",
"bottom": "0mm",
"left": "0mm"
}
},
"browser": {
"timeout": 20000,
"disableAnimations": true,
"viewport": {
"width": 400,
"height": 1000
},
"waitForSelector": "#order-number",
"waitAfter": 3000
},
"queue": {
"priority": 10
}
}
}'
```
## 2. Website Screenshot as PDF
Capture a full webpage and convert it to PDF with custom viewport.
```bash
curl -X POST http://localhost:3000/api/pdf/from-url \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "website-capture-github",
"url": "https://github.com",
"options": {
"browser": {
"viewport": { "width": 1920, "height": 1080 },
"timeout": 30000
}
}
}'
```
## 3. Authenticated Page PDF
Generate PDF from a page that requires authentication headers.
```bash
curl -X POST http://localhost:3000/api/pdf/from-url \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "dashboard-report",
"url": "https://app.example.com/dashboard",
"options": {
"browser": {
"extraHTTPHeaders": {
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"X-API-Key": "your-api-key"
},
"timeout": 60000
},
"pdf": {
"format": "A4",
"printBackground": true
}
}
}'
```
## 4. Single Page Application (SPA) PDF
Wait for dynamic content to load before generating PDF.
```bash
curl -X POST http://localhost:3000/api/pdf/from-url \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "spa-dashboard",
"url": "https://app.example.com/analytics",
"options": {
"browser": {
"viewport": { "width": 1440, "height": 900 },
"waitForSelector": "#charts-loaded",
"waitAfter": 3000,
"timeout": 90000
},
"pdf": {
"format": "A3",
"printBackground": true,
"landscape": true
}
}
}'
```
::: tip
Use `waitForSelector` to wait for a specific element that indicates the page is fully loaded, then `waitAfter` for additional time to ensure all animations complete.
:::
## 5. High Priority Report
Generate a PDF with high priority that jumps ahead in the queue.
```bash
curl -X POST http://localhost:3000/api/pdf/from-html \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "urgent-report-q4",
"html": "Q4 Financial Report - URGENT
Generated: 2025-01-15
| Metric | Value | Change |
|---|
| Revenue | $1.2M | +15% |
| Expenses | $800K | +5% |
| Profit | $400K | +35% |
",
"options": {
"pdf": {
"format": "Letter",
"printBackground": true
},
"queue": {
"priority": 10
}
}
}'
```
::: info Priority Levels
Priority ranges from 1 (lowest) to 10 (highest). Default is 5. Higher priority jobs are processed first.
:::
## 6. Animated Page with Animations Disabled
Generate PDF from a page with CSS animations, ensuring elements are fully visible.
```bash
curl -X POST http://localhost:3000/api/pdf/from-url \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "landing-page-pdf",
"url": "https://example.com/animated-landing",
"options": {
"browser": {
"viewport": { "width": 1920, "height": 1080 },
"disableAnimations": true,
"waitAfter": 1000
},
"pdf": {
"format": "A4",
"printBackground": true
}
}
}'
```
::: tip Why disable animations?
CSS animations can cause elements to be captured mid-animation, resulting in invisible or partially visible elements. The `disableAnimations` option ensures all elements are in their final state.
:::
## 7. Custom Size Social Media Card
Generate a PDF with custom dimensions for social media export.
```bash
curl -X POST http://localhost:3000/api/pdf/from-html \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "social-card-promo",
"html": "New Feature Released!
Check out our latest updates
",
"options": {
"browser": {
"viewport": { "width": 1200, "height": 630 }
},
"pdf": {
"width": 1200,
"height": 630,
"printBackground": true
}
}
}'
```
## Checking Job Status
After submitting a request, check the status:
```bash
curl http://localhost:3000/api/pdf/status/invoice-2025-001
```
Response:
```json
{
"requestedKey": "invoice-2025-001",
"status": "completed",
"filePath": "pdf-files/15-01-2025/invoice-2025-001__15-01-2025_10-30-45.pdf",
"createdAt": "2025-01-15T10:30:40.000Z",
"updatedAt": "2025-01-15T10:30:45.000Z"
}
```
## Downloading the PDF
Once the status is `completed`, download the PDF:
```bash
curl -O http://localhost:3000/api/pdf/download/invoice-2025-001
```
## Screenshot Examples
### 8. Full Page Screenshot
Capture a full webpage as a PNG image.
```bash
curl -X POST http://localhost:3000/api/screenshot/from-url \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "homepage-screenshot",
"url": "https://github.com",
"options": {
"browser": {
"viewport": { "width": 1920, "height": 1080 }
},
"screenshot": {
"type": "png",
"fullPage": true
}
}
}'
```
### 9. JPEG Screenshot with Quality
Generate a compressed JPEG screenshot.
```bash
curl -X POST http://localhost:3000/api/screenshot/from-url \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "compressed-capture",
"url": "https://example.com",
"options": {
"browser": {
"viewport": { "width": 1280, "height": 720 }
},
"screenshot": {
"type": "jpeg",
"quality": 80,
"fullPage": false
}
}
}'
```
### 10. Screenshot with Transparent Background
Capture an element with transparent background (PNG only).
```bash
curl -X POST http://localhost:3000/api/screenshot/from-html \
-H "Content-Type: application/json" \
-d '{
"requestedKey": "transparent-logo",
"html": "LOGO
",
"options": {
"browser": {
"viewport": { "width": 200, "height": 200 }
},
"screenshot": {
"type": "png",
"omitBackground": true,
"fullPage": false
}
}
}'
```
### Checking Screenshot Status
```bash
curl http://localhost:3000/api/screenshot/status/homepage-screenshot
```
Response:
```json
{
"requestedKey": "homepage-screenshot",
"status": "completed",
"filePath": "pdf-files/15-01-2025/homepage-screenshot__15-01-2025_10-30-45.png",
"createdAt": "2025-01-15T10:30:40.000Z",
"updatedAt": "2025-01-15T10:30:45.000Z"
}
```
### Downloading the Screenshot
Once the status is `completed`, download the screenshot:
```bash
curl -O http://localhost:3000/api/screenshot/download/homepage-screenshot
```
---
---
url: /chromium-pdf-service/guide/file-storage.md
---
# File Storage
## PDF Files
PDFs are organized in daily folders:
```
pdf-files/
├── 25-12-2025/
│ ├── invoice-123__25-12-2025_14-30-45.pdf
│ ├── report-456__25-12-2025_15-45-00.pdf
│ └── order-789__error__25-12-2025_16-00-30.png
├── 26-12-2025/
│ └── ...
```
## Filename Formats
**PDF filename format:**
```
{requestedKey}__{dd}-{mm}-{yyyy}_{hh}-{mm}-{ss}.pdf
```
Example: `invoice-123__25-12-2025_14-30-45.pdf`
**Error screenshot format:**
```
{requestedKey}__error__{dd}-{mm}-{yyyy}_{hh}-{mm}-{ss}.png
```
Example: `order-789__error__25-12-2025_16-00-30.png`
## Error Screenshots
When PDF generation fails, the service automatically captures a screenshot of the page state for debugging. The screenshot is saved in the same daily folder as the PDF would have been.
The error message will include the screenshot path:
```
Timeout 30000ms exceeded (screenshot: pdf-files/25-12-2025/my-key__error__25-12-2025_14-30-45.png)
```
---
---
url: /chromium-pdf-service/guide/getting-started.md
---
# Getting Started
Chromium PDF Service is a simple PDF generation service built with Fastify, TypeScript, Playwright, and Docker.
::: tip Suitable Use Cases
This service is designed for internal tools, proof of concepts, development environments, and trusted networks. For public-facing production deployments, additional security hardening (authentication, rate limiting, etc.) is recommended.
:::
## Features
* **PDF Generation**: Generate PDFs from HTML content, URLs, or uploaded HTML files
* **Screenshot Capture**: PNG/JPEG screenshots with full-page, viewport, or region clipping
* **Queue System**: Built-in job queue with priority support, status tracking, and cancellation
* **Queue Persistence**: Jobs survive service restarts (saved to `data/queue.json`)
* **Idempotent Requests**: Same `requestedKey` returns existing file if already completed
* **Custom Dimensions**: Use predefined formats (A4, Letter) or custom width/height
* **Disable Animations**: Option to disable CSS animations for reliable rendering
* **Error Screenshots**: Captures page screenshot on failure for debugging
* **Docker Ready**: Pre-built multi-arch images on GitHub Container Registry
* **Health Checks**: Kubernetes-compatible health, readiness, and liveness endpoints
* **Security**: Rate limiting, API authentication, CORS, URL validation, HTML sanitization
* **Logging**: Structured JSON logging with Pino (stdout + daily log files)
## Quick Start
### Using Pre-built Docker Image (Recommended)
The fastest way to get started:
```bash
# Pull and run the latest image
docker run -d \
--name pdf-service \
-p 3000:3000 \
-v $(pwd)/pdf-files:/app/pdf-files \
ghcr.io/chromium-pdf/chromium-pdf-service:latest
# Test the service
curl http://localhost:3000/health
```
Or with Docker Compose:
```yaml
# docker-compose.yml
services:
pdf-service:
image: ghcr.io/chromium-pdf/chromium-pdf-service:latest
ports:
- "3000:3000"
volumes:
- ./pdf-files:/app/pdf-files
```
```bash
docker-compose up -d
```
### Build Locally with Docker Compose
```bash
# Build and start the service
docker-compose up -d --build
# View logs
docker-compose logs -f
# Stop the service
docker-compose down
```
### Local Development
```bash
# Install dependencies
npm install
# Install Playwright browsers
npx playwright install chromium
# Run in development mode
npm run dev
# Build for production
npm run build
# Start production server
npm start
```
## Job Status Values
| Status | Description |
|--------|-------------|
| `queued` | Job is waiting in queue |
| `processing` | Job is being processed |
| `completed` | PDF generated successfully |
| `failed` | PDF generation failed (screenshot captured) |
| `cancelled` | Job was cancelled |
---
---
url: /chromium-pdf-service/guide/logging.md
---
# Logging
Logs are written to both stdout and daily JSON log files.
## Log Files
Logs are stored in the `logs` directory with daily rotation:
```
logs/
├── 25-12-2025.json
├── 26-12-2025.json
└── ...
```
**Log file format:** `dd-mm-yyyy.json`
## Log Structure
Each line in the log file is a JSON object containing:
```json
{
"level": 30,
"time": 1735123456789,
"service": "chromium-pdf-service",
"requestedKey": "invoice-123",
"msg": "Job completed"
}
```
### Log Levels
| Level | Name | Description |
|-------|------|-------------|
| 10 | trace | Very detailed debugging |
| 20 | debug | Debugging information |
| 30 | info | General information |
| 40 | warn | Warning messages |
| 50 | error | Error messages |
| 60 | fatal | Fatal errors |
## Configuration
Set log level via environment variable:
```bash
LOG_LEVEL=debug npm start
```
Or in Docker:
```yaml
environment:
- LOG_LEVEL=info
```
---
---
url: /chromium-pdf-service/api/pdf-options.md
---
# PDF Options
PDF options control the output format and appearance of the generated PDF.
## Options Reference
| Option | Type | Description |
|--------|------|-------------|
| `format` | string | `A4`, `Letter`, `Legal`, `A3`, `A5` |
| `width` | string/number | Custom width (e.g., `800`, `"10in"`, `"25cm"`) |
| `height` | string/number | Custom height (e.g., `600`, `"8in"`, `"20cm"`) |
| `landscape` | boolean | Landscape orientation |
| `margin` | object | `{ top, right, bottom, left }` |
| `printBackground` | boolean | Print background graphics |
| `scale` | number | Scale factor (0.1 - 2) |
| `headerTemplate` | string | HTML template for header |
| `footerTemplate` | string | HTML template for footer |
| `displayHeaderFooter` | boolean | Show header/footer |
::: warning
Use either `format` OR `width`/`height`, not both. Custom dimensions override format.
:::
## Examples
### Standard Format
```json
{
"options": {
"pdf": {
"format": "A4",
"printBackground": true
}
}
}
```
### Custom Dimensions
```json
{
"options": {
"pdf": {
"width": 400,
"height": 800,
"printBackground": true
}
}
}
```
### With Units
```json
{
"options": {
"pdf": {
"width": "10in",
"height": "8in"
}
}
}
```
### Custom Margins
```json
{
"options": {
"pdf": {
"format": "A4",
"margin": {
"top": "20mm",
"right": "15mm",
"bottom": "20mm",
"left": "15mm"
}
}
}
}
```
### Landscape Orientation
```json
{
"options": {
"pdf": {
"format": "A4",
"landscape": true
}
}
}
```
### Header and Footer
```json
{
"options": {
"pdf": {
"format": "A4",
"displayHeaderFooter": true,
"headerTemplate": "My Header
",
"footerTemplate": "Page of
"
}
}
}
```
---
---
url: /chromium-pdf-service/development/playground.md
---
# Playground App
A Vue.js [playground app](https://github.com/chromium-pdf/playground) is included for testing the PDF and Screenshot APIs interactively.
---
---
url: /chromium-pdf-service/api/queue-options.md
---
# Queue Options
Queue options control job priority and processing order.
## Options Reference
| Option | Type | Description |
|--------|------|-------------|
| `priority` | number | Priority level 1-10 (higher = processed first) |
## Request Options
| Option | Type | Description |
|--------|------|-------------|
| `reCreate` | boolean | Force recreate PDF even if one already exists |
## Examples
### High Priority Job
```json
{
"requestedKey": "urgent-report",
"url": "https://example.com",
"options": {
"queue": {
"priority": 10
}
}
}
```
### Force Recreate
```json
{
"requestedKey": "existing-report",
"url": "https://example.com",
"reCreate": true
}
```
::: tip
By default, if a PDF with the same `requestedKey` already exists and is completed, the service will return the existing PDF. Use `reCreate: true` to force regeneration.
:::
---
---
url: /chromium-pdf-service/guide/queue.md
---
# Queue System
The service includes a built-in job queue with priority support, status tracking, and automatic persistence.
## Features
* **Priority Support**: Jobs with higher priority (1-10) are processed first
* **Status Tracking**: Track job progress from queued to completed
* **Cancellation**: Cancel pending or processing jobs
* **Persistence**: Queue state survives service restarts
## Queue Persistence
Queue state is saved to `data/queue.json` and restored on service restart:
* Processing jobs are reset to "queued" on restart
* Completed/failed jobs are preserved
* Automatic retry on failure
## Queue Statistics
Get queue statistics via API:
```bash
GET /api/pdf/queue
```
Response:
```json
{
"total": 10,
"queued": 5,
"processing": 2,
"completed": 2,
"failed": 1,
"cancelled": 0
}
```
## Priority
Use the `priority` option to control job processing order:
```json
{
"requestedKey": "urgent-report",
"url": "https://example.com",
"options": {
"queue": {
"priority": 10
}
}
}
```
Priority levels: 1 (lowest) to 10 (highest). Default is 5.
---
---
url: /chromium-pdf-service/api/screenshot-options.md
---
# Screenshot Options
Screenshot options control the output format and capture settings for generated screenshots.
## Options Reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `type` | string | `"png"` | Output format: `"png"` or `"jpeg"` |
| `quality` | number | - | JPEG quality (0-100). Only valid for JPEG |
| `fullPage` | boolean | `true` | Capture full scrollable page |
| `clip` | object | - | Capture specific region `{ x, y, width, height }` |
| `omitBackground` | boolean | `false` | Transparent background (PNG only) |
| `scale` | string | - | Scale mode: `"css"` or `"device"` |
::: warning
* Use either `fullPage` OR `clip`, not both
* `quality` is only valid when `type` is `"jpeg"`
* `omitBackground` only works with PNG format
:::
## Examples
### PNG Screenshot (Default)
```json
{
"options": {
"screenshot": {
"type": "png",
"fullPage": true
}
}
}
```
### JPEG with Quality
```json
{
"options": {
"screenshot": {
"type": "jpeg",
"quality": 80,
"fullPage": true
}
}
}
```
::: tip
Lower quality values result in smaller file sizes. A quality of 80 is usually a good balance between size and visual quality.
:::
### Capture Specific Region
```json
{
"options": {
"screenshot": {
"type": "png",
"fullPage": false,
"clip": {
"x": 100,
"y": 200,
"width": 800,
"height": 600
}
}
}
}
```
The `clip` object defines:
* `x`: Left offset in pixels
* `y`: Top offset in pixels
* `width`: Width of the region in pixels
* `height`: Height of the region in pixels
### Transparent Background
```json
{
"options": {
"screenshot": {
"type": "png",
"omitBackground": true
}
}
}
```
::: tip
For transparent backgrounds to work, ensure your HTML content has a transparent background style:
```html
```
:::
### Viewport-Only Screenshot
To capture only the visible viewport (not full page):
```json
{
"options": {
"browser": {
"viewport": { "width": 1920, "height": 1080 }
},
"screenshot": {
"type": "png",
"fullPage": false
}
}
}
```
### High-DPI Screenshot
Use `scale: "device"` for high-DPI (retina) screenshots:
```json
{
"options": {
"screenshot": {
"type": "png",
"fullPage": true,
"scale": "device"
}
}
}
```
## Combining with Browser Options
Screenshot options work alongside browser options for full control:
```json
{
"requestedKey": "full-control-screenshot",
"url": "https://example.com",
"options": {
"browser": {
"viewport": { "width": 1920, "height": 1080 },
"timeout": 30000,
"waitForSelector": "#content-loaded",
"waitAfter": 1000,
"disableAnimations": true
},
"screenshot": {
"type": "png",
"fullPage": true,
"omitBackground": false
}
}
}
```
## Output Files
Screenshots are saved to the configured output directory with the following naming convention:
```
{outputDir}/{date}/{requestedKey}__{timestamp}.{ext}
```
Example: `pdf-files/15-01-2025/my-screenshot__15-01-2025_10-30-45.png`
---
---
url: /chromium-pdf-service/guide/security.md
---
# Security
This page covers the security features available in Chromium PDF Service.
::: tip Suitable Use Cases
This service is designed for internal tools, proof of concepts, development environments, and trusted networks. For public-facing production deployments, enable the security features described below.
:::
## Rate Limiting
Prevent abuse by limiting the number of requests per client.
```bash
# Environment variables
RATE_LIMIT_MAX=100 # Max requests per window (default: 100)
RATE_LIMIT_WINDOW=60000 # Window in milliseconds (default: 60000 = 1 minute)
```
Rate limit headers are included in responses:
* `x-ratelimit-limit` - Maximum requests allowed
* `x-ratelimit-remaining` - Requests remaining in current window
* `x-ratelimit-reset` - Time when the window resets
* `retry-after` - Seconds to wait (when limit exceeded)
## API Key Authentication
Restrict access to authorized clients using API keys.
```bash
# Single key
API_KEYS=my-secret-key
# Multiple keys (comma-separated)
API_KEYS=key1,key2,key3
```
Clients must include the key in the `X-API-Key` header:
```bash
curl -H "X-API-Key: my-secret-key" http://localhost:3000/api/pdf/html
```
### Public Endpoints
These endpoints do not require authentication:
* `GET /` - Service info
* `GET /health` - Health check
* `GET /health/ready` - Readiness probe
* `GET /health/live` - Liveness probe
* `GET /docs/*` - API documentation (development only)
## CORS Configuration
Control which origins can access the API.
```bash
# Allow specific origins (comma-separated)
ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com
# Leave empty to allow all origins (default)
ALLOWED_ORIGINS=
```
## Security Headers
HTTP security headers are automatically added via Helmet:
| Header | Value |
|--------|-------|
| `X-Content-Type-Options` | `nosniff` |
| `X-Frame-Options` | `SAMEORIGIN` |
| `X-XSS-Protection` | `0` |
| `Strict-Transport-Security` | Enabled for HTTPS |
## URL Validation (SSRF Protection)
Prevent Server-Side Request Forgery when generating PDFs from URLs.
### Block Private IPs
By default, private IP addresses are blocked:
```bash
# Enabled by default
BLOCK_PRIVATE_IPS=true
# Blocked ranges:
# - localhost, 127.x.x.x
# - 10.x.x.x
# - 172.16-31.x.x
# - 192.168.x.x
# - 169.254.x.x (link-local)
```
### Domain Allowlist
Restrict URLs to specific domains:
```bash
# Only allow these domains
ALLOWED_URL_DOMAINS=example.com,trusted.org
# Subdomains are automatically allowed
# e.g., api.example.com is allowed when example.com is in the list
```
### Blocked Protocols
These protocols are always blocked:
* `file://`
* `javascript:`
* `data:`
* `vbscript:`
Only `http://` and `https://` are allowed.
## HTML Sanitization
Prevent XSS attacks in HTML content.
```bash
# Enable sanitization (disabled by default for compatibility)
SANITIZE_HTML=true
```
When enabled, the following are removed:
### Blocked Tags
* `