Website Screenshots,
On Demand
One function call captures any URL with a headless browser, caches it on disk, and returns a base64 data URL — so your app never re-launches a browser for the same page twice.
npm i @npmforge/snapforgeSee live demoSelf-hosted
Run the capture service on your own infra. Your screenshots never leave your servers.
Disk-cached
First capture stored on disk. Repeat requests within the TTL window skip the headless browser entirely.
TypeScript-first
Fully typed SnapshotResult keeps your image handlers compile-safe from request to render.
Full-page capture
Configure viewport width, height, and fullPage mode per request or set sensible project defaults.
TTL control
Set a default cache duration on the client and override it per-request for fine-grained refresh control.
Zero runtime deps
The SDK ships with no runtime dependencies — just the native fetch API and Node's Buffer.
The Problem
Headless browsers are expensive to spin up. Without a capture service, every screenshot request cold-starts Puppeteer, burns memory, and produces no cache.
// Repetitive: manual Puppeteer setup on every call
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 });
await page.goto(url, { waitUntil: "networkidle2" });
const buf = await page.screenshot({ fullPage: true });
await browser.close();
// No caching — same URL re-launches a full browser
const dataUrl = `data:image/png;base64,${buf.toString("base64")}`;import { createSnapforgeClient } from "@npmforge/snapforge";
const client = createSnapforgeClient({ baseUrl, apiKey });
const snapshot = await client.getSnapshot({
url: "https://example.com",
fullPage: true,
width: 1440,
});
// snapshot.dataUrl ready to embed in <img src>
// snapshot.cached tells you if it was served from disk
if (snapshot.cached) scheduleRefresh(snapshot.expiresAt);Consistent output, every time
Every getSnapshot() call returns the same typed object — whether the image was freshly captured or served from cache.
| Field | Type | Example | Description |
|---|---|---|---|
dataUrl | string | "data:image/png;base64,..." | Base64-encoded screenshot ready to embed in an img src. |
cached | boolean | true | Whether the response was served from disk cache. |
capturedAt | string | "2024-01-15T10:30:00Z" | ISO timestamp of when the screenshot was taken. |
expiresAt | string | "2024-01-15T10:35:00Z" | ISO timestamp of when the cache entry expires. |
ttlSeconds | number | 300 | Cache duration in seconds that was applied. |
mimeType | string | "image/png" | MIME type of the returned image. |
sourceUrl | string | "https://example.com" | The original URL that was captured. |
bytes | Uint8Array | Uint8Array(89203) | Raw image bytes for custom processing or storage. |
Works out of the box with
Live Playground
Each card below is a real getSnapshot() call rendered server-side. Badges show whether the image was served from cache or freshly captured.
Vercel
Loading…Velocity UI
Loading…Mozilla
Loading…Get started in seconds
Deploy the capture service and call getSnapshot() from any Node environment.
npm i @npmforge/snapforge