Rendering
Pictify renders HTML/CSS templates to various output formats. This page covers rendering options, formats, and optimization.
Images
| Format | Extension | Best For | Transparency |
|---|
| PNG | .png | Screenshots, graphics with transparency | Yes |
| JPEG | .jpg | Photos, smaller file sizes | No |
| WebP | .webp | Modern browsers, best compression | Yes |
Documents
| Format | Extension | Best For |
|---|
| PDF | .pdf | Print, documents, multi-page content |
Animated
| Format | Extension | Best For |
|---|
| GIF | .gif | Animations, short loops |
Rendering Options
Dimensions
const image = await pictify.renderHtml({
html: '<h1>Hello</h1>',
width: 1200, // Output width in pixels (default: 1280)
height: 630, // Output height in pixels (default: 720)
});
Maximum dimensions: 4000x4000 pixels for authenticated users, 2000x2000 for public/trial.
renderHtml writes a PNG by default. Set format to choose the output type — it maps to the /image endpoint’s fileExtension:
const image = await pictify.renderHtml({
html: '<h1>Hello</h1>',
format: 'jpeg' // 'png' | 'jpg' | 'jpeg' | 'webp' | 'pdf' (default: png)
});
The /image endpoint does not expose a quality knob. To control raster compression, render through a template (pictify.render({ templateId, quality }), where quality is 0.1–1.0).
Selector
Capture a specific element instead of the full page:
const image = await pictify.renderHtml({
html: '<div><header>...</header><main id="content">Target</main></div>',
selector: '#content' // Only capture this element
});
Image Generation
From HTML
const image = await pictify.renderHtml({
html: `
<div style="width: 1200px; height: 630px; background: #667eea;">
<h1 style="color: white;">Hello World</h1>
</div>
`,
width: 1200,
height: 630
});
console.log(image.url);
From URL
Capture a screenshot of any URL:
const screenshot = await pictify.renderUrl({
url: 'https://example.com/page',
width: 1200,
height: 630
});
console.log(screenshot.url);
From Template
Render a saved template with variables:
const result = await pictify.render({
templateId: 'template-id',
variables: {
title: 'Dynamic Content'
}
});
// Access the rendered image (result.url is a convenience accessor for results[0].url)
console.log(result.url);
console.log(result.results[0].url);
Layout Variants
Templates can have multiple layout variants for different platforms (e.g., Twitter, Facebook, Instagram). Render a specific layout or multiple layouts at once:
// Render a specific layout
const single = await pictify.render({
templateId: 'template-id',
variables: { title: 'Hello' },
layout: 'twitter-post'
});
// Render multiple layouts in one request (max 20)
const result = await pictify.renderLayouts({
templateId: 'template-id',
variables: { title: 'Hello' },
layouts: ['default', 'twitter-post', 'facebook-post']
});
// Each layout is a separate result
result.results.forEach(r => {
console.log(`${r.name} (${r.width}x${r.height}): ${r.url}`);
});
The default layout is the base template. Use the layout key (e.g., twitter-post, facebook-post) to render a specific variant. Layout keys are set when creating variants via the AI Resize feature in the editor.
From Canvas Data
Render FabricJS canvas data directly via the POST /image/canvas REST endpoint. The SDKs don’t wrap this endpoint, so call it with your HTTP client of choice:
curl -X POST https://api.pictify.io/image/canvas \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"engine": "fabric",
"fabricJSData": {
"version": "5.3.0",
"objects": [
{ "type": "rect", "fill": "#667eea", "width": 1200, "height": 630 },
{ "type": "textbox", "text": "Hello", "fill": "white", "top": 100, "left": 100 }
]
},
"variables": { "greeting": "Hello World" },
"width": 1200,
"height": 630
}'
See the Create Canvas Image reference for the full request schema.
GIF Generation
From HTML Animation
Capture CSS animations:
const gif = await pictify.renderGif({
html: `
<div class="animated">
<style>
@keyframes fade { 0% { opacity: 0; } 100% { opacity: 1; } }
.animated { animation: fade 2s infinite; }
</style>
<h1>Animated Text</h1>
</div>
`,
width: 600,
height: 400
});
console.log(gif.url, gif.animationLength);
From a Live URL
Record motion on a live page:
const gif = await pictify.renderGif({
url: 'https://example.com/animated-page',
width: 800,
height: 600,
quality: 'high' // 'low' | 'medium' | 'high' (default: medium)
});
Quality Presets
| Preset | Frame Rate | Max Duration | File Size |
|---|
low | 10 fps | 10s | Small |
medium | 15 fps | 15s | Medium |
high | 24 fps | 30s | Large |
PDF Generation
From a Template (SDK)
The quickest way to produce a PDF is to render a template with format: 'pdf':
const result = await pictify.render({
templateId: 'invoice-template',
variables: {
invoiceNumber: 'INV-001',
},
format: 'pdf'
});
console.log(result.url);
Paper Sizes & Multi-Page (REST)
The dedicated PDF endpoints (POST /pdf/render and POST /pdf/multi-page) accept paper-size presets, margins, and per-page content. The SDKs don’t wrap these directly, so call them with your HTTP client:
# Single page with a paper-size preset and margins
curl -X POST https://api.pictify.io/pdf/render \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateUid": "invoice-template",
"variables": { "invoiceNumber": "INV-001" },
"preset": "A4",
"margins": { "top": 20, "bottom": 20, "left": 20, "right": 20 }
}'
# Multi-page: one page per variable set
curl -X POST https://api.pictify.io/pdf/multi-page \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateUid": "report-template",
"variableSets": [
{ "pageTitle": "Introduction", "content": "..." },
{ "pageTitle": "Chapter 1", "content": "..." },
{ "pageTitle": "Conclusion", "content": "..." }
],
"preset": "A4"
}'
See the PDF Generation reference for all options.
PDF Presets
| Preset | Dimensions | Use Case |
|---|
A4 | 210 × 297 mm | Standard documents |
Letter | 8.5 × 11 in | US letter size |
Legal | 8.5 × 14 in | Legal documents |
A3 | 297 × 420 mm | Larger documents |
A5 | 148 × 210 mm | Booklets |
custom | User-defined | Custom sizes |
# Custom PDF size
curl -X POST https://api.pictify.io/pdf/render \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateUid": "template-id",
"preset": "custom",
"customSize": { "width": 800, "height": 600 }
}'
Screenshot a Section of a Page
To capture a specific region of a live page, screenshot the URL and crop to an element with selector:
const screenshot = await pictify.renderUrl({
url: 'https://stripe.com/pricing',
selector: '#pricing', // crop to this element
width: 1200,
height: 630
});
console.log(screenshot.url);
Prefer natural language? The Pictify MCP server lets AI agents request screenshots conversationally — the SDKs themselves expose the direct renderUrl call shown above.
The template render endpoint always returns a results array, even for single-layout renders:
{
"results": [
{
"layout": "default",
"name": "Default",
"url": "https://cdn.pictify.io/renders/abc123.png",
"width": 1200,
"height": 630,
"format": "png",
"id": "abc123"
}
],
"errors": [],
"totalLayouts": 1,
"totalRendered": 1,
"totalErrors": 0,
"templateUid": "TEMPLATE_UID"
}
Multi-layout response:
{
"results": [
{
"layout": "default",
"name": "Default",
"url": "https://cdn.pictify.io/renders/abc123.png",
"width": 1080,
"height": 1080,
"format": "png"
},
{
"layout": "twitter-post",
"name": "Twitter/X Post",
"url": "https://cdn.pictify.io/renders/def456.png",
"width": 1200,
"height": 675,
"format": "png"
}
],
"errors": [],
"totalLayouts": 2,
"totalRendered": 2,
"totalErrors": 0,
"templateUid": "TEMPLATE_UID"
}
Other render endpoints (HTML, URL, GIF) return:
{
"url": "https://cdn.pictify.io/renders/abc123.png",
"id": "abc123",
"width": 1200,
"height": 630,
"createdAt": "2026-01-29T10:30:00Z"
}
User Storage
If you’ve configured user storage (S3, R2, etc.), renders are also uploaded to your storage:
{
"url": "https://cdn.pictify.io/renders/abc123.png",
"userStorageUrl": "https://your-bucket.s3.amazonaws.com/renders/abc123.png"
}
Batch Rendering
Render many variable sets from a single template. Batch rendering is asynchronous: submitting returns immediately with a batchId, and the job runs in the background.
Request
const job = await pictify.renderBatch({
templateId: 'product-card',
variableSets: [
{ title: 'Card 1' },
{ title: 'Card 2' },
], // max 100 per batch
layouts: ['default', 'twitter-post'], // optional; or `layout: 'square'`
});
// { batchId, status, totalItems }
console.log(job.batchId);
Pass layout (string) for a single variant, or layouts (array) for multiple variants per item.
Tracking Progress
Poll getBatchResults(batchId) to track status. The poll response reports per-item index, success, and variables — but not rendered URLs:
{
"batchId": "batch_abc123",
"status": "completed",
"progress": 100,
"totalItems": 2,
"completedItems": 2,
"failedItems": 0,
"results": [
{ "index": 0, "success": true, "variables": ["title"] },
{ "index": 1, "success": true, "variables": ["title"] }
],
"errors": []
}
const status = await pictify.getBatchResults(job.batchId);
console.log(status.status, status.completedItems, 'of', status.totalItems);
for (const item of status.results) {
console.log(`item ${item.index}: success=${item.success}`);
}
Rendered URLs are not returned by the poll endpoint. Final image URLs are delivered via the render.completed webhook — subscribe to webhooks to collect batch output. See the Batch Processing guide for the full workflow.
- Use appropriate dimensions - Don’t render larger than needed
- Choose the right format - JPEG for photos, PNG for graphics, WebP for best compression
- Tune template quality - for template renders,
quality 0.9 is usually indistinguishable from 1.0
- Batch similar renders - Use batch rendering for many images from one template
- Cache rendered images - Store URLs and reuse instead of re-rendering