Skip to main content

Rendering

Pictify renders HTML/CSS templates to various output formats. This page covers rendering options, formats, and optimization.

Output Formats

Images

FormatExtensionBest ForTransparency
PNG.pngScreenshots, graphics with transparencyYes
JPEG.jpgPhotos, smaller file sizesNo
WebP.webpModern browsers, best compressionYes

Documents

FormatExtensionBest For
PDF.pdfPrint, documents, multi-page content

Animated

FormatExtensionBest For
GIF.gifAnimations, 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.

Format

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.11.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

PresetFrame RateMax DurationFile Size
low10 fps10sSmall
medium15 fps15sMedium
high24 fps30sLarge

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

PresetDimensionsUse Case
A4210 × 297 mmStandard documents
Letter8.5 × 11 inUS letter size
Legal8.5 × 14 inLegal documents
A3297 × 420 mmLarger documents
A5148 × 210 mmBooklets
customUser-definedCustom 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.

Response Format

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.

Performance Tips

  1. Use appropriate dimensions - Don’t render larger than needed
  2. Choose the right format - JPEG for photos, PNG for graphics, WebP for best compression
  3. Tune template quality - for template renders, quality 0.9 is usually indistinguishable from 1.0
  4. Batch similar renders - Use batch rendering for many images from one template
  5. Cache rendered images - Store URLs and reuse instead of re-rendering