Documentation
Everything you need to use Openkova.
Conversion modes
Openkova supports three ways to produce screenshots:
- HTML Snippet — Paste raw HTML into the textarea. The server wraps it in a full document, renders it in a headless Chromium browser at 1280×800, and returns a PNG screenshot.
- Files — Upload one or more
.htmlor.htmfiles. Each file is rendered individually and returned as a separate screenshot, processed in order. - URL / Crawl — Provide any public URL. Openkova fetches the page, extracts all same-origin links, and screenshots up to 10 pages (depth 1 follows direct links; depth 2 follows their links once more). Pages are captured sequentially.
Sessions
Every conversion is associated with a session — a UUID that groups your screenshots together. The session ID is returned in every API response and stored in an openkova_session HTTP-only cookie (7-day expiry). Pass it back as sessionId in subsequent requests to keep results in the same gallery. If you omit it, a new session is created automatically.
Storage retention: 24 hours. Screenshots are automatically deleted 24 hours after the session was last written to. The server runs a cleanup pass every hour. Download your images before then — use the Download All button or the GET /api/session/:sessionId/download endpoint to grab everything as a ZIP.
Streaming responses (SSE)
All three convert endpoints respond with a Server-Sent Events (SSE) stream rather than a single JSON blob. This lets the UI (and your own code) display live progress as the browser launches, pages load, and snapshots are taken.
Each line in the stream is a JSON event in one of three shapes:
// A step in progress
{ "type": "progress", "message": "Launching virtual browser" }
// Final success — stream closes after this
{ "type": "done", "message": "Done — 3 screenshots saved", "data": { ... } }
// Unrecoverable error — stream closes after this
{ "type": "error", "message": "Conversion failed" }The data field on done events contains the same payload that was previously returned as JSON (see per-endpoint details below).
The Set-Cookie header for the session is set on the streaming response itself, so cookies work normally even though there is no JSON body.
Consuming the stream (JavaScript)
const res = await fetch('/api/convert/snippet', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ html: '<h1>Hello</h1>' }),
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// SSE events are separated by double newline
const parts = buffer.split('\n\n');
buffer = parts.pop() ?? '';
for (const part of parts) {
const line = part.split('\n').find(l => l.startsWith('data: '));
if (!line) continue;
const event = JSON.parse(line.slice(6));
if (event.type === 'progress') console.log(event.message);
if (event.type === 'done') console.log('Result:', event.data);
if (event.type === 'error') console.error(event.message);
}
}POST /api/convert/snippet
Renders a raw HTML string and returns a single screenshot. The HTML is wrapped in a minimal full document with a reset stylesheet before rendering.
Request — Content-Type: application/json
{
"html": "<h1>Hello</h1>", // required — raw HTML string
"sessionId": "uuid" // optional — omit to create a new session
}Done event data:
{
"sessionId": "uuid",
"imageId": "uuid",
"url": "/api/image/{sessionId}/{imageId}"
}POST /api/convert/file
Accepts one or more HTML files as multipart form data and returns one screenshot per file. Files are rendered sequentially in the order they are submitted.
Request — Content-Type: multipart/form-data
files File[] // required — one or more .html/.htm files
sessionId string // optional form fieldDone event data:
{
"sessionId": "uuid",
"results": [
{ "imageId": "uuid", "filename": "index.html", "url": "/api/image/..." },
...
]
}POST /api/convert/url
Crawls a public URL and screenshots discovered pages 10 at a time.
Request (crawl mode) — Content-Type: application/json
{
"url": "https://example.com", // required — valid absolute URL
"depth": 1, // optional — 1 (default) or 2
"sessionId": "uuid" // optional
}Request (paginate mode) — pass pre-known URLs to screenshot without re-crawling:
{
"urls": ["https://example.com/page-11", ...], // required
"sessionId": "uuid", // required — use the session from the first request
"offset": 10, // how many pages were already captured
"total": 25 // total discovered in the original crawl
}Done event data:
{
"sessionId": "uuid",
"results": [{ "imageId": "uuid", "url": "https://example.com/" }, ...],
"remaining": ["https://example.com/page-11", ...],
"total": 25
}GET /api/image/:sessionId/:id
Returns a single PNG screenshot with Content-Type: image/png. Responses are cached for 1 hour (Cache-Control: public, max-age=3600, immutable). Returns 404 if the image does not exist.
GET /api/session/:sessionId/download
Downloads all screenshots in a session as a single .zip file. Returns 404 if the session has no images.
GET /api/session/:sessionId
Returns all image IDs associated with a session.
{ "images": ["uuid1", "uuid2", ...] }