Skip to content

Deploying URL-to-PNG

Introduction

URL-to-PNG is a simple, self-hosted service that generates screenshots of websites. Using a headless browser, it captures any webpage and returns it as a PNG image, making it perfect for generating thumbnails, preview images, and visual snapshots of web content.

Built with Node.js and Puppeteer, URL-to-PNG provides a clean REST API that accepts a URL and returns a screenshot. No complex configuration needed - just send a request with the URL you want to capture and receive an image in response.

Key highlights of URL-to-PNG:

  • Simple API: Single endpoint that accepts URL and returns image
  • Puppeteer Powered: Full Chrome rendering for accurate screenshots
  • Customizable Output: Control viewport size, image dimensions, and format
  • Fast Response: Optimized for quick screenshot generation
  • Self-Hosted: Full control over your screenshot infrastructure
  • Privacy Focused: URLs never sent to third-party services
  • Caching Support: Optional caching for repeated requests
  • Open Source: MIT licensed for full transparency

This guide walks through deploying URL-to-PNG on Klutch.sh using Docker, configuring the service, and integrating it with your applications.

Why Deploy URL-to-PNG on Klutch.sh

Deploying URL-to-PNG on Klutch.sh provides several advantages for screenshot generation:

Simplified Deployment: Klutch.sh automatically detects your Dockerfile and builds URL-to-PNG without complex configuration. Push to GitHub, and your screenshot service deploys automatically.

Persistent Storage: Attach persistent volumes for caching screenshots and reducing repeated rendering.

HTTPS by Default: Klutch.sh provides automatic SSL certificates, ensuring secure API access.

Scalable Resources: Allocate CPU and memory based on your screenshot volume. Headless Chrome benefits from adequate resources.

Always-On Service: Your screenshot API remains accessible 24/7 for your applications.

Prerequisites

Before deploying URL-to-PNG on Klutch.sh, ensure you have:

  • A Klutch.sh account
  • A GitHub account with a repository for your URL-to-PNG configuration
  • Basic familiarity with Docker and REST APIs
  • Applications that need screenshot functionality
  • (Optional) A custom domain for your screenshot service

Understanding URL-to-PNG Architecture

URL-to-PNG is built on a straightforward stack:

Node.js Server: Express-based API server handling requests.

Puppeteer: Headless Chrome automation for rendering pages.

Chromium: The browser engine that renders web pages.

Sharp (optional): Image processing for optimization.

Preparing Your Repository

To deploy URL-to-PNG on Klutch.sh, create a GitHub repository containing your Dockerfile.

Repository Structure

url-to-png-deploy/
├── Dockerfile
└── .dockerignore

Creating the Dockerfile

Create a Dockerfile in the root of your repository:

FROM node:18-slim
# Install Chromium dependencies
RUN apt-get update && apt-get install -y \
chromium \
fonts-ipafont-gothic \
fonts-wqy-zenhei \
fonts-thai-tlwg \
fonts-kacst \
fonts-symbola \
fonts-noto \
fonts-freefont-ttf \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# Set Puppeteer to use installed Chromium
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
# Create app directory
WORKDIR /app
# Install URL-to-PNG
RUN npm init -y && npm install url-to-png
# Set environment variables
ENV PORT=3000
ENV API_KEY=${API_KEY}
# Create cache directory
RUN mkdir -p /app/cache
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "node_modules/url-to-png/index.js"]

Custom Server Configuration

For more control, create a custom server.js:

const express = require('express');
const puppeteer = require('puppeteer');
const app = express();
const PORT = process.env.PORT || 3000;
const API_KEY = process.env.API_KEY;
// API key middleware
app.use((req, res, next) => {
if (API_KEY && req.query.api_key !== API_KEY) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
});
// Screenshot endpoint
app.get('/screenshot', async (req, res) => {
const { url, width = 1280, height = 800, fullPage = false } = req.query;
if (!url) {
return res.status(400).json({ error: 'URL parameter required' });
}
try {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.setViewport({ width: parseInt(width), height: parseInt(height) });
await page.goto(url, { waitUntil: 'networkidle0' });
const screenshot = await page.screenshot({
type: 'png',
fullPage: fullPage === 'true'
});
await browser.close();
res.type('image/png').send(screenshot);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

Environment Variables Reference

VariableRequiredDefaultDescription
PORTNo3000Port for the API server
API_KEYNo-Optional API key for authentication
CACHE_DIRNo/app/cacheDirectory for cached screenshots
CACHE_TTLNo3600Cache time-to-live in seconds

Deploying URL-to-PNG on Klutch.sh

Once your repository is prepared, follow these steps to deploy URL-to-PNG:

    Push Your Repository to GitHub

    Initialize your repository and push to GitHub:

    Terminal window
    git init
    git add Dockerfile .dockerignore
    git commit -m "Initial URL-to-PNG deployment configuration"
    git remote add origin https://github.com/yourusername/url-to-png-deploy.git
    git push -u origin main

    Create a New Project on Klutch.sh

    Navigate to the Klutch.sh dashboard and create a new project. Give it a descriptive name like “url-to-png” or “screenshot-api”.

    Create a New App

    Within your project, create a new app. Connect your GitHub account if you haven’t already, then select the repository containing your URL-to-PNG Dockerfile.

    Configure HTTP Traffic

    In the deployment settings:

    • Select HTTP as the traffic type
    • Set the internal port to 3000 (API server port)

    Set Environment Variables

    In the environment variables section, add the following:

    VariableValue
    API_KEYA secure API key (optional but recommended)
    CACHE_TTL3600 (1 hour cache)

    Attach Persistent Volumes

    Add persistent storage for caching:

    Mount PathRecommended SizePurpose
    /app/cache5 GBCached screenshots

    Deploy Your Application

    Click Deploy to start the build process. Klutch.sh will:

    • Detect your Dockerfile automatically
    • Build the container image
    • Attach the persistent volumes
    • Start the URL-to-PNG container
    • Provision an HTTPS certificate

    Access URL-to-PNG

    Once deployment completes, access your URL-to-PNG instance at https://your-app-name.klutch.sh/health to verify it’s running.

Using the API

Basic Screenshot

Generate a simple screenshot:

GET https://your-app.klutch.sh/screenshot?url=https://example.com

Custom Dimensions

Specify viewport size:

GET https://your-app.klutch.sh/screenshot?url=https://example.com&width=1920&height=1080

Full Page Screenshot

Capture the entire page:

GET https://your-app.klutch.sh/screenshot?url=https://example.com&fullPage=true

With Authentication

If API key is configured:

GET https://your-app.klutch.sh/screenshot?url=https://example.com&api_key=YOUR_KEY

Integration Examples

HTML Image Tag

Embed screenshots directly in HTML:

<img src="https://your-app.klutch.sh/screenshot?url=https://example.com&width=400&height=300"
alt="Example.com Preview">

JavaScript Fetch

Fetch screenshot programmatically:

const response = await fetch(
`https://your-app.klutch.sh/screenshot?url=${encodeURIComponent(url)}&api_key=${apiKey}`
);
const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);

Python Integration

import requests
response = requests.get(
'https://your-app.klutch.sh/screenshot',
params={'url': 'https://example.com', 'api_key': 'YOUR_KEY'}
)
with open('screenshot.png', 'wb') as f:
f.write(response.content)

Advanced Configuration

Caching

Implement caching to improve performance:

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
function getCacheKey(url, width, height) {
return crypto.createHash('md5')
.update(`${url}-${width}-${height}`)
.digest('hex');
}
function getCachedScreenshot(key) {
const cachePath = path.join('/app/cache', `${key}.png`);
if (fs.existsSync(cachePath)) {
const stats = fs.statSync(cachePath);
const age = (Date.now() - stats.mtimeMs) / 1000;
if (age < parseInt(process.env.CACHE_TTL || 3600)) {
return fs.readFileSync(cachePath);
}
}
return null;
}

Wait Options

Control page loading behavior:

  • waitUntil: 'load' - Wait for load event
  • waitUntil: 'domcontentloaded' - Wait for DOM ready
  • waitUntil: 'networkidle0' - Wait for network quiet
  • waitUntil: 'networkidle2' - Wait for 2 or fewer connections

Custom User Agent

Set a custom user agent:

await page.setUserAgent('URL-to-PNG Screenshot Service');

Production Best Practices

Security

  • API Key Protection: Always use API keys in production
  • Rate Limiting: Implement rate limiting to prevent abuse
  • URL Validation: Validate and sanitize input URLs
  • Private Network Access: Consider blocking internal/private URLs

Performance

  • Resource Allocation: Chromium needs adequate memory (2GB+ recommended)
  • Caching: Cache screenshots to reduce repeated rendering
  • Connection Pooling: Reuse browser instances for better performance

Monitoring

  • Track request latency
  • Monitor memory usage
  • Alert on error rates
  • Log failed URLs for debugging

Troubleshooting Common Issues

Screenshots Failing

Symptoms: API returns errors or blank images.

Solutions:

  • Verify URL is accessible
  • Check for JavaScript errors on target page
  • Increase timeout settings
  • Verify Chromium has enough memory

Slow Performance

Symptoms: Screenshots take too long to generate.

Solutions:

  • Enable caching
  • Increase server resources
  • Reduce viewport size
  • Use faster waitUntil options

Memory Issues

Symptoms: Container crashes or restarts.

Solutions:

  • Increase memory allocation
  • Close browser instances properly
  • Limit concurrent screenshots
  • Monitor memory usage

Additional Resources

Conclusion

Deploying URL-to-PNG on Klutch.sh gives you a reliable, self-hosted screenshot service accessible from anywhere. The combination of URL-to-PNG’s simple API and Klutch.sh’s deployment automation means you can generate website previews without relying on third-party services.

With customizable output, caching support, and full control over your infrastructure, URL-to-PNG provides everything you need for programmatic screenshot generation. Your URLs and images remain private, processed on your own secure infrastructure.