Ruby SDK
The official Pictify SDK for Ruby provides an idiomatic Ruby interface for the Pictify API — generate images, PDFs, and GIFs from raw HTML, live URLs, and reusable templates.
Installation
Add to your Gemfile:
Then run:
Or install directly:
Quick Start
require "pictify"
client = Pictify::Client.new(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>",
width: 1200,
height: 630
)
puts image.url
# Render a template
result = client.render(
template_id: "XL13XACH2V",
variables: { name: "Ada", company: "Pictify" }
)
puts result.url
Configuration
The client is constructed with a keyword api_key. Every request is sent with an Authorization: Bearer <API_KEY> header.
client = Pictify::Client.new(
api_key: "your-api-key",
base_url: "https://api.pictify.io", # optional: API base URL (default: https://api.pictify.io)
timeout: 30, # 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. ENV["PICTIFY_API_KEY"]) and never expose it in client-side code or public repositories.
Rendering Images
From HTML — POST /image
Returns an ImageResult with url, id, and created_at.
image = client.render_html(
html: "<div>Hello</div>",
css: "div { color: blue; }", # injected as a <style> tag before the HTML
width: 1200, # default 1280
height: 630, # default 720
selector: "#card", # crop to a specific element (optional)
format: :png # :png, :jpg, :jpeg, :webp, :pdf — mapped to fileExtension
)
puts image.url # CDN URL
puts image.id # image id
puts image.created_at # ISO timestamp
The /image endpoint accepts a single html field, so any css you pass is injected into a <style> tag prepended to the HTML.
From a live URL (screenshot) — POST /image
image = client.render_url(
url: "https://example.com",
width: 1280,
height: 720,
selector: "#main", # optional
format: :png # optional
)
puts image.url
Rendering Templates
Single render — POST /templates/:uid/render
Returns a RenderResult results array (one item per rendered layout). result.url is a convenience accessor for the first result’s URL.
result = client.render(
template_id: "XL13XACH2V",
variables: { name: "Ada", company: "Pictify" },
format: :png, # :png, :jpg, :jpeg, :webp, :pdf
quality: 0.9, # raster quality 0.1–1.0
width: 1200, # optional override
height: 630 # optional override
)
puts result.url # results.first.url
puts result.template_uid
result.results.each do |item|
puts "#{item.layout}: #{item.url} (#{item.width}x#{item.height})"
end
You can also render a single named variant via render(..., layout: "square").
Multiple layout variants — POST /templates/:uid/render
Templates can have multiple layout variants (e.g. landscape, square, story) created via AI Resize in the Pictify editor. Render several in one call (max 20); layouts that fail land in errors.
result = client.render_layouts(
template_id: "XL13XACH2V",
variables: { name: "Ada" },
layouts: ["default", "twitter-post", "instagram-story"]
)
result.results.each do |item|
puts "#{item.layout}: #{item.url} (#{item.width}x#{item.height})"
end
result.errors.each do |err|
puts "#{err.layout} failed: #{err.error}"
end
puts "rendered #{result.total_rendered} of #{result.total_layouts}"
Rendering GIFs — POST /gif
Provide exactly one source: html, url, or template_id (+ optional variables). The source must contain motion (CSS animation, etc.). The { gif: {...} } envelope is flattened to a GifRenderResult.
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, # default 800
height: 200, # default 600
quality: :medium # :low, :medium, :high
)
puts gif.url
puts gif.uid
puts 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")
Static content produces no frames and returns a render error (HTTP 422).
Batch Rendering (async) — POST /templates/:uid/batch-render
Batch rendering is asynchronous. Submitting returns a batch_id immediately (HTTP 202); poll get_batch_results to track progress.
job = client.render_batch(
template_id: "XL13XACH2V",
variable_sets: [
{ name: "Card 1", company: "X" },
{ name: "Card 2", company: "Y" }
],
format: :png,
quality: 0.9, # optional
concurrency: 5, # optional, 1–10
layouts: ["default", "twitter-post"] # optional
)
puts job.batch_id
puts job.status # "pending"
puts job.total_items
# Poll for progress
results = client.get_batch_results(job.batch_id)
puts "status: #{results.status} (#{results.progress}%)"
puts "completed: #{results.completed_items} / #{results.total_items}"
results.results.each do |item|
puts "Item #{item.index}: success=#{item.success?} vars=#{item.variables}"
end
The poll endpoint reports per-item index, success, and variables but not rendered URLs — URLs are delivered via the render.completed webhook.
Template Management
# Get a template by UID — GET /templates/:uid
template = client.get_template("XL13XACH2V")
puts "Template: #{template.name} (#{template.uid})"
template.variable_definitions.each do |var|
puts " - #{var.name} (#{var.type})"
end
# List templates — GET /templates
result = client.list_templates(page: 1, limit: 20, sort: :newest)
result.templates.each { |t| puts "#{t.uid}: #{t.name}" }
puts "total: #{result.pagination.total}"
# Create a template from HTML — POST /templates
# Variables are auto-discovered from {{variableName}} tokens.
template = client.create_template(
html: "<div>Hi {{firstName}}</div>",
name: "Welcome Card",
width: 600,
height: 200,
output_format: "image" # "image" | "pdf"
)
puts template.uid
Error Handling
begin
result = client.render(template_id: "XL13XACH2V", variables: { name: "Ada" })
rescue Pictify::AuthenticationError
puts "Invalid API key"
rescue Pictify::TemplateNotFoundError => e
puts "Template not found: #{e.message}"
rescue Pictify::QuotaExceededError
puts "Render quota exceeded"
rescue Pictify::RateLimitError => e
puts "Rate limited. Retry after: #{e.retry_after}s"
rescue Pictify::RenderError => e
puts "Render/validation failed: #{e.message}"
puts e.errors # field-level validation errors when present (422)
rescue Pictify::ServerError => e
puts "Server error: #{e.message}"
rescue Pictify::NetworkError => e
puts "Network error: #{e.message}"
rescue Pictify::TimeoutError
puts "Request timed out"
rescue Pictify::Error => e
puts "Error: #{e.message}"
end
| Status | Error class |
|---|
| 401 | Pictify::AuthenticationError |
| 402 | Pictify::QuotaExceededError |
| 404 | Pictify::TemplateNotFoundError |
| 422 | Pictify::RenderError (carries errors) |
429 (quota_exceeded) | Pictify::QuotaExceededError |
| 429 (other) | Pictify::RateLimitError |
| other 4xx | Pictify::RenderError |
| 5xx | Pictify::ServerError |
Only 5xx responses and network failures are retried (with exponential backoff); 4xx responses (including 429) are never retried.
Framework Example — Rails
class OgImagesController < ApplicationController
def show
client = Pictify::Client.new(api_key: ENV["PICTIFY_API_KEY"])
result = client.render(
template_id: "og-image-template",
variables: { title: params[:title] }
)
redirect_to result.url, allow_other_host: true
end
end
API Reference
See the API Reference for full endpoint documentation.