A small, self-hosted website screenshot and storyboard tool powered by Playwright.
- Full-page, viewport, and CSS-selector captures
- Zoomable and pannable preview and storyboard canvases
- PNG and JPEG export
- Per-IP rate limiting and concurrent capture limits
- Capture timeouts and bounded screenshot dimensions
- Private-network and cloud-metadata blocking
- Short-lived, memory-bounded capture cache
- Optional Umami product analytics
Requirements: Node.js 20+ and the system dependencies required by Playwright.
npm ci
npx playwright install chromium
npm startOpen http://localhost:3010.
Run the checks with:
npm run check
npm testThe Docker image is the recommended deployment path because its Playwright version matches the bundled browser:
docker build -t snap .
docker run --rm -p 3010:3010 snapThe included railway.json deploys this Dockerfile directly on Railway.
Copy .env.example if you want to change the defaults.
| Variable | Default | Purpose |
|---|---|---|
PORT |
3010 |
HTTP port |
TRUST_PROXY_HOPS |
1 |
Trusted reverse-proxy hops; Railway uses one |
RATE_LIMIT_MAX |
30 |
Capture requests allowed per IP and window |
RATE_LIMIT_WINDOW_MS |
600000 |
Rate-limit window |
MAX_CONCURRENT_CAPTURES |
2 |
Captures allowed at once |
CAPTURE_TIMEOUT_MS |
30000 |
Overall capture timeout |
CACHE_TTL_MS |
600000 |
Capture cache lifetime |
MAX_CACHE_SIZE |
30 |
Maximum cached captures |
MAX_CACHE_BYTES |
50331648 |
Maximum cache memory |
ALLOWED_TARGET_PORTS |
80,443,8080,8443 |
Permitted destination ports |
CORS_ORIGINS |
empty | Comma-separated external origins allowed to call the API |
The in-memory rate limiter and cache are intended for a single application instance. If you scale horizontally, put these controls in a shared store and enforce private-network egress rules at the platform or firewall level too.
The server validates the initial URL, redirects, subresources, resolved IP addresses, and outbound browser tunnels. Localhost, private networks, reserved networks, metadata addresses, credentials in URLs, and unexpected ports are blocked.
Browser-based URL fetchers remain security-sensitive. Keep the container and Playwright image updated, run it with minimal cloud permissions, and retain platform-level egress restrictions as defense in depth.
Please report vulnerabilities privately through the repository's Security Advisories. Use normal GitHub issues for bugs and feature requests. See SECURITY.md for details.
The public UI loads Umami using the website ID in public/index.html.
Analytics events contain capture type, cache status, broad duration buckets,
and UI actions. Target URLs, CSS selectors, and captured images are not sent.
Remove the Umami script tags if you do not want analytics in your deployment.
Open an issue before a large change. Keep pull requests focused and run
npm run check && npm test before submitting.