
Research
/Security News
737 Chrome VPN Extensions Linked to Brand Impersonation and Browser Traffic Redirection
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.
@pictify/sdk
Advanced tools
Official Node.js SDK for Pictify — generate images, PDFs, and GIFs from HTML, live URLs, and reusable templates.
npm install @pictify/sdk
# or
yarn add @pictify/sdk
# or
pnpm add @pictify/sdk
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: 'your-template-uid',
variables: { name: 'Ada', company: 'Pictify' },
});
console.log('Image URL:', result.url);
AuthenticationError, RateLimitError, QuotaExceededError, and moreconst pictify = new Pictify({
apiKey: string, // Required: your Pictify API key
baseUrl?: string, // Optional: API base URL (default: https://api.pictify.io)
timeout?: number, // Optional: request timeout in ms (default: 30000)
retries?: number, // Optional: number of retries on 5xx/network errors (default: 3)
});
renderHtml(options)Render an image (or PDF) directly from HTML. POST /image.
const image = await pictify.renderHtml({
html: '<div style="padding:40px">Hello</div>',
css: 'div { color: blue; }', // optional — inlined into a <style> tag
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)
});
// Result: { url, id, createdAt }
console.log(image.url);
renderUrl(options)Screenshot a live URL. POST /image with url.
const image = await pictify.renderUrl({
url: 'https://example.com',
width: 1280,
height: 720,
selector: '.hero', // optional
format: 'png', // optional
});
// Result: { url, id, createdAt }
console.log(image.url);
render(options)Render a single image (or PDF) from a template. POST /templates/:uid/render.
const result = await pictify.render({
templateId: 'template-uid',
variables: { title: 'My Post', author: 'Ada' },
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
});
// The response is a results[] envelope. `result.url` is a convenience
// accessor for 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
}
renderLayouts(options)Render multiple layout variants of a template in one call. POST /templates/:uid/render with layouts.
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: 'template-uid',
variables: { title: 'Hello World' },
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}`);
}
renderGif(options)Render an animated GIF from raw HTML, a live URL, or a template. POST /gif. Provide exactly one source.
const gif = await pictify.renderGif({
html: '<style>@keyframes p{...}</style><div class="anim">Hi</div>',
// or: url: 'https://example.com'
// or: templateId: 'template-uid', variables: { name: 'Ada' }
width: 400, // optional (default: 800)
height: 200, // optional (default: 600)
quality: 'medium', // optional: 'low' | 'medium' | 'high' (default: medium)
});
// Result: { url, uid, width, height, animationLength }
console.log(gif.url);
The source HTML/URL must contain motion (e.g. a CSS animation). Static content produces no frames and returns an error.
renderBatch(options) + getBatchResults(batchId)Submit an async batch render of a template across many variable sets. POST /templates/:uid/batch-render returns immediately with a batchId; poll getBatchResults to track progress.
const job = await pictify.renderBatch({
templateId: 'template-uid',
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 —
getBatchResultsreports per-item{ index, success, variables }(anderroron failures). Final image URLs are delivered via therender.completedwebhook. Subscribe to webhooks to collect batch output.
getTemplate(templateId)Get a single template by its UID. GET /templates/:uid.
const template = await pictify.getTemplate('template-uid');
// { uid, name, html, width, height, engine, outputFormat,
// variables: string[], variableDefinitions: [...], createdAt, ... }
console.log(template.uid, template.name);
listTemplates(options)List templates in your account. GET /templates.
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);
createTemplate(options)Create a template from HTML. 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);
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: 'template-uid' });
} 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);
}
}
| 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 |
const { Pictify } = require('@pictify/sdk');
const pictify = new Pictify({ apiKey: process.env.PICTIFY_API_KEY });
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-template-uid',
variables: { title, description },
});
res.redirect(result.url!);
});
// 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-template-uid',
variables: { title },
});
return NextResponse.redirect(result.url!);
}
MIT — see LICENSE for details.
FAQs
Official Pictify Node.js SDK for generating images from HTML templates
We found that @pictify/sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
The campaign amassed more than 75,000 installs by targeting Russian-speaking users seeking access to blocked services.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.