Node.js SDK
The official Pictify SDK for Node.js provides a type-safe, promise-based interface for the Pictify API — generate images, PDFs, and GIFs from raw HTML, live URLs, and reusable templates.
Installation
Quick Start
import { Pictify } from '@pictify/sdk';
const pictify = new Pictify({
apiKey: process.env.PICTIFY_API_KEY!,
});
// Render raw HTML to a PNG
const image = await pictify.renderHtml({
html: '<div style="font-size:48px;padding:40px">Hello World</div>',
width: 1200,
height: 630,
});
console.log('Image URL:', image.url);
// Render a reusable template
const result = await pictify.render({
templateId: 'XL13XACH2V',
variables: { name: 'Ada', company: 'Pictify' },
});
console.log('Image URL:', result.url);
Configuration
The client is constructed with a config object. apiKey is required; every request is sent with an Authorization: Bearer <API_KEY> header.
const pictify = new Pictify({
apiKey: process.env.PICTIFY_API_KEY!, // Required: your Pictify API key
baseUrl: 'https://api.pictify.io', // Optional: API base URL (default: https://api.pictify.io)
timeout: 30000, // Optional: request timeout in ms (default: 30000)
retries: 3, // Optional: retries on 5xx / network errors (default: 3)
});
Keep your API key secret. Read it from an environment variable (PICTIFY_API_KEY) and never expose it in client-side code or public repositories.
Render an Image from HTML
renderHtml(options) — POST /image. Returns { url, id, createdAt }.
const image = await pictify.renderHtml({
html: '<div style="padding:40px">Hello</div>',
css: 'div { color: blue; }', // optional — inlined into a <style> tag before the HTML
width: 1200, // optional (default: 1280)
height: 630, // optional (default: 720)
selector: '#card', // optional — crop to a specific element
format: 'png', // optional: 'png' | 'jpg' | 'jpeg' | 'webp' | 'pdf' (default: png)
});
console.log(image.url); // https://cdn.pictify.io/...
console.log(image.id);
console.log(image.createdAt);
The /image endpoint accepts a single html field, so any css you pass is injected into a <style> tag prepended to the HTML. format is mapped to the endpoint’s fileExtension.
Screenshot a Live URL
renderUrl(options) — POST /image with url. Returns { url, id, createdAt }.
const screenshot = await pictify.renderUrl({
url: 'https://example.com',
width: 1280, // optional (default: 1280)
height: 720, // optional (default: 720)
selector: '.hero', // optional — crop to a specific element
format: 'png', // optional
});
console.log(screenshot.url);
Render a Template
render(options) — POST /templates/:uid/render. Returns a results[] envelope with a convenience url getter (results[0]?.url).
const result = await pictify.render({
templateId: 'XL13XACH2V',
variables: { name: 'Ada', company: 'Pictify' },
format: 'png', // optional: 'png' | 'jpg' | 'jpeg' | 'webp' | 'pdf' (default: png)
quality: 0.9, // optional render quality, 0.1–1.0 (default: 0.9)
width: 1200, // optional
height: 630, // optional
});
// `result.url` is a convenience accessor for result.results[0]?.url
console.log(result.url);
console.log(result.results[0]); // { layout, url, width, height, format, name, id, createdAt }
The response shape:
{
results: RenderResultItem[]; // one entry per rendered layout
errors: RenderErrorEntry[]; // { layout, error } for any failed layout
totalLayouts: number;
totalRendered: number;
totalErrors: number;
templateUid: string;
url: string | undefined; // convenience getter == results[0]?.url
}
Render a Specific Layout
Pass a single layout to render one named variant.
const result = await pictify.render({
templateId: 'XL13XACH2V',
variables: { name: 'Ada' },
layout: 'square',
});
Render Multiple Layouts
renderLayouts(options) — POST /templates/:uid/render with layouts (max 20).
Templates can have layout variants (e.g. square, story) created via AI Resize in the Pictify editor. Use default for the base layout. Missing or invalid layouts come back in errors[] rather than throwing.
const result = await pictify.renderLayouts({
templateId: 'XL13XACH2V',
variables: { name: 'Ada' },
layouts: ['default', 'square', 'story'], // max 20
});
for (const item of result.results) {
console.log(`${item.layout}: ${item.url} (${item.width}x${item.height})`);
}
for (const err of result.errors) {
console.log(`${err.layout} failed: ${err.error}`);
}
Render an Animated GIF
renderGif(options) — POST /gif. Provide exactly one source: html, url, or templateId. The API’s nested { gif: {...} } envelope is flattened to { url, uid, width, height, animationLength }.
const gif = await pictify.renderGif({
html: '<style>@keyframes p{0%{opacity:.2}50%{opacity:1}100%{opacity:.2}}div{font-size:40px;padding:30px;animation:p 2s infinite}</style><div>Hi</div>',
// or: url: 'https://example.com'
// or: templateId: 'XL13XACH2V', variables: { name: 'Ada' }
width: 400, // optional (default: 800)
height: 200, // optional (default: 600)
quality: 'medium', // optional: 'low' | 'medium' | 'high' (default: medium)
});
console.log(gif.url, gif.uid, gif.animationLength);
The source HTML/URL must contain motion (e.g. a CSS animation). Static content produces no frames and returns a render error (HTTP 422).
Batch Rendering (async)
renderBatch(options) — POST /templates/:uid/batch-render. Returns immediately (HTTP 202) with a batchId; poll getBatchResults(batchId) (GET /templates/batch/:batchId/results) to track progress.
const job = await pictify.renderBatch({
templateId: 'XL13XACH2V',
variableSets: [
{ name: 'Ada', company: 'Pictify' },
{ name: 'Grace', company: 'Pictify' },
], // max 100 per batch
format: 'png', // optional
quality: 0.9, // optional, 0.1–1.0
concurrency: 5, // optional, 1–10 (default: 5)
// layout: 'square' or layouts: ['default', 'square'] — optional
});
// { batchId, status, totalItems }
console.log(job.batchId);
// Poll for progress.
const status = await pictify.getBatchResults(job.batchId);
console.log(status.status); // 'pending' | 'processing' | 'completed' | 'partial' | 'failed' | 'cancelled'
console.log(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. getBatchResults reports per-item { index, success, variables } (and error on failures). Final image URLs are delivered via the render.completed webhook — subscribe to webhooks to collect batch output.
Templates
Get a Template
getTemplate(templateId) — GET /templates/:uid. Unwraps the { template } envelope.
const template = await pictify.getTemplate('XL13XACH2V');
// { uid, name, html, width, height, engine, outputFormat,
// variables: string[], variableDefinitions: [...], createdAt, ... }
console.log(template.uid, template.name);
List Templates
listTemplates(options) — GET /templates. Returns { templates, pagination }.
const { templates, pagination } = await pictify.listTemplates({
page: 1, // optional (default: 1)
limit: 20, // optional, max 100 (default: 12)
sort: 'newest', // optional: 'newest' | 'oldest' | 'name'
});
console.log(pagination.total, 'templates');
for (const t of templates) console.log(t.uid, t.name);
Create a Template
createTemplate(options) — POST /templates. Variables are auto-discovered from {{variableName}} tokens in the HTML body.
const template = await pictify.createTemplate({
html: '<div>Hi {{firstName}}</div>',
name: 'Welcome Card', // optional
width: 600, // optional
height: 200, // optional
variableDefinitions: [], // optional — auto-extracted from the HTML when omitted
outputFormat: 'image', // optional: 'image' | 'pdf'
});
console.log(template.uid);
Error Handling
All API errors throw a typed subclass of PictifyError.
import {
Pictify,
PictifyError,
AuthenticationError,
TemplateNotFoundError,
RateLimitError,
QuotaExceededError,
RenderError,
} from '@pictify/sdk';
try {
const result = await pictify.render({ templateId: 'XL13XACH2V' });
} catch (error) {
if (error instanceof RateLimitError) {
console.log('Rate limited — slow down');
} else if (error instanceof QuotaExceededError) {
console.log('Quota exceeded — upgrade your plan');
} else if (error instanceof RenderError) {
console.error('Render/validation failed:', error.message, error.errors);
} else if (error instanceof PictifyError) {
console.error('Pictify error:', error.code, error.message);
} else {
throw error;
}
}
Error Types
| Error Class | Code | HTTP | Description |
|---|
AuthenticationError | INVALID_API_KEY | 401 | Invalid or missing API key |
QuotaExceededError | QUOTA_EXCEEDED | 402 / 429 | Render quota exceeded |
TemplateNotFoundError | TEMPLATE_NOT_FOUND | 404 | Template (or batch job) not found |
RenderError | RENDER_FAILED | 422 (and other 4xx) | Render or input validation failed (error.errors holds field-level details) |
RateLimitError | RATE_LIMIT_EXCEEDED | 429 | Too many requests |
ServerError | SERVER_ERROR | 5xx | Server-side failure |
NetworkError | NETWORK_ERROR | — | Network request failed |
TimeoutError | TIMEOUT | — | Request timed out |
Only 5xx and network failures are retried (with exponential backoff); 4xx responses are never retried.
CommonJS Support
const { Pictify } = require('@pictify/sdk');
const pictify = new Pictify({ apiKey: process.env.PICTIFY_API_KEY });
TypeScript Support
The SDK is written in TypeScript and exports all types:
import {
Pictify,
ImageResult,
RenderResult,
RenderResultItem,
GifRenderResult,
BatchRenderResult,
BatchResults,
Template,
ListTemplatesResult,
ImageFormat,
GifQuality,
} from '@pictify/sdk';
Next.js Integration
Route Handler (OG image)
// app/api/og/route.ts
import { Pictify } from '@pictify/sdk';
import { NextRequest, NextResponse } from 'next/server';
const pictify = new Pictify({ apiKey: process.env.PICTIFY_API_KEY! });
export async function GET(req: NextRequest) {
const title = req.nextUrl.searchParams.get('title') ?? '';
const result = await pictify.render({
templateId: 'og-image-template',
variables: { title },
});
return NextResponse.redirect(result.url!);
}
Express.js OG-image route
import express from 'express';
import { Pictify } from '@pictify/sdk';
const app = express();
const pictify = new Pictify({ apiKey: process.env.PICTIFY_API_KEY! });
app.get('/og-image', async (req, res) => {
const { title, description } = req.query as Record<string, string>;
const result = await pictify.render({
templateId: 'og-image-template',
variables: { title, description },
});
res.redirect(result.url!);
});
API Reference
See the API Reference for full endpoint documentation.