Python SDK
The official Pictify SDK for Python provides a simple, Pythonic interface for the Pictify API — generate images, PDFs, and GIFs from raw HTML, live URLs, and reusable templates. It ships sync (Pictify) and async (AsyncPictify) clients with an identical surface.
Installation
Quick Start
from pictify import Pictify
client = Pictify(api_key="your-api-key")
# Render raw HTML to a PNG
image = client.render_html(html="<div style='font-size:48px;padding:40px'>Hello World</div>")
print(image.url)
# Render a reusable template
result = client.render("XL13XACH2V", variables={"name": "Ada", "company": "Pictify"})
print(result.url) # results[0].url
Async Usage
import asyncio
from pictify import AsyncPictify
async def main():
async with AsyncPictify(api_key="your-api-key") as client:
image = await client.render_html(html="<div>Hello World</div>")
print(image.url)
asyncio.run(main())
Configuration
The client is constructed with a keyword api_key. Every request is sent with an Authorization: Bearer <API_KEY> header.
client = Pictify(
api_key="your-api-key",
base_url="https://api.pictify.io", # optional: API base URL (default: https://api.pictify.io)
timeout=30.0, # optional: request timeout in seconds (default: 30)
max_retries=3, # optional: retries on 5xx / network errors (default: 3)
)
Keep your API key secret. Read it from an environment variable (e.g. os.environ["PICTIFY_API_KEY"]) and never expose it in client-side code or public repositories.
Both clients are context managers and expose close():
with Pictify(api_key="your-api-key") as client:
...
async with AsyncPictify(api_key="your-api-key") as client:
...
Render an Image from HTML
render_html(html, *, css=None, width=None, height=None, selector=None, format=None) — POST /image. Returns an ImageResult with url, id, and created_at.
image = client.render_html(
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)
)
print(image.url, image.id, image.created_at)
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
render_url(url, *, width=None, height=None, selector=None, format=None) — POST /image with url. Returns an ImageResult.
image = client.render_url(url="https://example.com", width=1280, height=720)
print(image.url)
Render a Template
render(template_id, *, variables=None, format=None, quality=None, width=None, height=None, layout=None, layouts=None) — POST /templates/:uid/render.
The response is a results envelope; result.url is a convenience accessor for results[0].url.
result = client.render(
"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
)
print(result.url)
print(result.results[0]) # RenderResultItem: layout, url, width, height, format, name, id, created_at
Render a Specific Layout
result = client.render(
"XL13XACH2V",
variables={"name": "Ada"},
layout="square",
)
Render Multiple Layouts
render_layouts(template_id, layouts, *, variables=None, format=None, quality=None, width=None, height=None) — POST /templates/:uid/render with layouts (max 20).
Each successful layout appears in results; missing/invalid layouts appear in errors.
result = client.render_layouts(
"XL13XACH2V",
layouts=["default", "square", "story"],
variables={"name": "Ada"},
)
for item in result.results:
print(item.layout, item.url, f"{item.width}x{item.height}")
for err in result.errors:
print("failed:", err.layout, err.error)
Render an Animated GIF
render_gif(*, html=None, url=None, template_id=None, variables=None, width=None, height=None, quality=None) — POST /gif.
Provide exactly one source: html, url, or template_id. The {gif: {...}} envelope is flattened.
gif = client.render_gif(
html="<style>@keyframes p{0%{opacity:.2}50%{opacity:1}100%{opacity:.2}}div{animation:p 2s infinite}</style><div>Hi</div>",
width=400, # optional (default: 800)
height=200, # optional (default: 600)
quality="medium", # optional: 'low' | 'medium' | 'high' (default: medium)
)
print(gif.url, gif.uid, gif.animation_length)
# From a template
gif = client.render_gif(template_id="XL13XACH2V", variables={"name": "Ada"})
# From a live URL
gif = client.render_gif(url="https://example.com/animated-page")
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)
render_batch(template_id, variable_sets, *, format=None, quality=None, concurrency=None, layout=None, layouts=None) — POST /templates/:uid/batch-render.
Submitting returns immediately (HTTP 202) with a batch_id. Poll get_batch_results for progress.
job = client.render_batch(
"XL13XACH2V",
variable_sets=[
{"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)
)
print(job.batch_id, job.status, job.total_items)
get_batch_results(batch_id) — GET /templates/batch/:batchId/results.
status = client.get_batch_results(job.batch_id)
print(status.status, status.completed_items, "/", status.total_items)
for item in status.results:
print(item.index, item.success, item.variables) # no URLs (see webhook)
Rendered URLs are not returned by the poll endpoint. Per-item records carry {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
get_template(template_id) — GET /templates/:uid.
template = client.get_template("XL13XACH2V")
print(template.uid, template.name)
print([v.name for v in (template.variable_definitions or [])])
List Templates
list_templates(*, page=None, limit=None, sort=None) — GET /templates. Returns a ListTemplatesResult with templates and pagination.
result = client.list_templates(page=1, limit=20, sort="newest")
for t in result.templates:
print(t.uid, t.name)
print(result.pagination.total, result.pagination.has_next)
Create a Template
create_template(html, *, name=None, width=None, height=None, variable_definitions=None, output_format=None) — POST /templates. Variables are auto-discovered from {{variableName}} tokens.
template = client.create_template(
html="<div>Hi {{first_name}}</div>",
name="Welcome Card",
width=600,
height=200,
output_format="image", # optional: 'image' | 'pdf'
)
print(template.uid)
Error Handling
from pictify import (
Pictify,
PictifyError,
AuthenticationError,
TemplateNotFoundError,
RateLimitError,
QuotaExceededError,
RenderError,
ServerError,
)
client = Pictify(api_key="your-api-key")
try:
result = client.render("XL13XACH2V", variables={"name": "Ada"})
except AuthenticationError:
print("Invalid API key")
except TemplateNotFoundError:
print("Template not found")
except RateLimitError as e:
print(f"Rate limited. Retry after: {e.retry_after}s")
except QuotaExceededError:
print("Render quota exceeded")
except RenderError as e:
print(f"Render/validation failed: {e.message}; field errors: {e.errors}")
except ServerError as e:
print(f"Server error: {e.message}")
except PictifyError as e:
print(f"Error: {e.message}")
Status → error mapping: 401 → AuthenticationError, 402 → QuotaExceededError, 404 → TemplateNotFoundError, 422 → RenderError (with field-level errors), 429 → QuotaExceededError when code == "quota_exceeded" else RateLimitError, other 4xx → RenderError, 5xx → ServerError. Only 5xx and network errors are retried.
Type Hints
The SDK ships full type hints and Pydantic result models:
from pictify import (
Pictify,
AsyncPictify,
ImageResult,
RenderResult,
RenderResultItem,
GifRenderResult,
BatchRenderResult,
BatchResults,
Template,
ListTemplatesResult,
ImageFormat,
GifQuality,
)
Django Integration
# views.py
from django.conf import settings
from django.http import HttpResponseRedirect
from pictify import Pictify
client = Pictify(api_key=settings.PICTIFY_API_KEY)
def og_image(request, slug):
post = Post.objects.get(slug=slug)
result = client.render(
"og-image-template",
variables={
"title": post.title,
"description": post.excerpt,
"author": post.author.name,
},
)
return HttpResponseRedirect(result.url)
API Reference
See the API Reference for full endpoint documentation.