Pictify Ruby SDK

Official Ruby SDK for Pictify — generate images, PDFs, and GIFs from raw HTML, live URLs, and reusable templates.

Installation

Add to your Gemfile:

gem "pictify"

Then run:

bundle install

Or install directly:

gem install pictify

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: "your-template-uid",
  variables: { name: "Ada", company: "Pictify" }
)
puts result.url

Configuration

client = Pictify::Client.new(
  api_key: "your-api-key",
  base_url: "https://api.pictify.io",  # Custom API URL
  timeout: 30,                         # Request timeout in seconds
  max_retries: 3                       # Max retry attempts (5xx / network only)
)

Rendering Images

From HTML — POST /image

image = client.render_html(
  html: "<div>Hello</div>",
  css: "div { color: blue; }",  # injected as a <style> tag before rendering
  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

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 results array (one item per rendered layout). result.url is a convenience accessor for the first result's URL.

result = client.render(
  template_id: "your-template-uid",
  variables: { title: "My Post", author: "Ada" },
  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

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: "your-template-uid",
  variables: { title: "Hello World" },
  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}"

You can also render a single named variant via render(..., layout: "square").

Rendering GIFs — POST /gif

Provide exactly one source: html, url, or template_id (+ optional variables). The source must contain motion (CSS animation, etc.).

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: "your-template-uid", variables: { name: "Ada" })

# From a live URL
gif = client.render_gif(url: "https://example.com/animated-page")

Batch Rendering (async) — POST /templates/:uid/batch-render

Batch rendering is asynchronous. Submitting returns a batch_id immediately; poll get_batch_results to track progress.

Note: the poll endpoint reports per-item index, success, and variables but not rendered URLs — URLs are delivered via the render.completed webhook.

job = client.render_batch(
  template_id: "your-template-uid",
  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

Template Management

# Get a template by UID — GET /templates/:uid
template = client.get_template("your-template-uid")
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: "your-template-uid", 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"])
    image = client.render(
      template_id: "og-image-template",
      variables: { title: params[:title] }
    )
    redirect_to image.url, allow_other_host: true
  end
end

License

MIT