--- 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": "

Invoice #2025-001

Date: January 15, 2025

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

MetricValueChange
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 * `