Ruby on Rails applications across every industry need screenshot functionality: SaaS dashboards that export visual reports, marketplaces that generate listing thumbnails, monitoring tools that capture UI state on alerts, and CMS platforms that preview published pages. Building a headless browser in your Rails stack adds significant infrastructure complexity. SnapAPI gives your Rails app a clean REST API that returns a screenshot of any URL in seconds.
This guide covers integrating SnapAPI into a Rails application using a service object pattern, handling async captures with ActiveJob, caching results with Rails cache, and deploying screenshot functionality to Heroku and Render.
Creating a SnapAPI Service Object in Rails
Rails service objects keep external API calls organized and testable. Create app/services/snap_api_service.rb to encapsulate all SnapAPI interactions:
require "net/http"
require "uri"
class SnapApiService
BASE_URL = "https://snapapi.pics/screenshot"
API_KEY = ENV["SNAPAPI_KEY"]
def self.capture(url, width: 1280, full_page: false)
uri = URI(BASE_URL)
uri.query = URI.encode_www_form(
access_key: API_KEY,
url: url,
viewport_width: width,
full_page: full_page
)
response = Net::HTTP.get_response(uri)
response.body if response.is_a?(Net::HTTPSuccess)
end
end
Store the API key in Rails credentials or an environment variable. Never hardcode it in source files that might be committed to version control. The service returns the raw PNG binary on success or nil on failure, which your controller can handle with a simple nil check.
Using Faraday for Cleaner HTTP Requests
Most Rails applications already use Faraday for HTTP requests. Add gem "faraday" to your Gemfile if it is not already present, then rewrite the service to use Faraday's cleaner DSL:
class SnapApiService
BASE_URL = "https://snapapi.pics"
def self.client
Faraday.new(BASE_URL) do |f|
f.response :raise_error
f.adapter Faraday.default_adapter
end
end
def self.capture(url, **opts)
response = client.get("/screenshot") do |req|
req.params[:access_key] = ENV["SNAPAPI_KEY"]
req.params[:url] = url
req.params.merge!(opts)
end
response.body
end
end
Background Screenshot Jobs with ActiveJob
Screenshot captures should run in the background rather than blocking the HTTP request cycle. Create a job at app/jobs/screenshot_job.rb:
class ScreenshotJob < ApplicationJob
queue_as :default
def perform(record_id, url)
data = SnapApiService.capture(url)
return unless data
key = "screenshots/#{record_id}.png"
# Upload to S3 using ActiveStorage or direct SDK call
upload_to_s3(key, data)
Record.find(record_id).update!(screenshot_key: key)
end
end
Enqueue the job from your controller when a new record is created: ScreenshotJob.perform_later(@record.id, @record.url). Use Sidekiq, Solid Queue, or Good Job as your ActiveJob backend. The user gets an immediate response while the screenshot generates asynchronously.
Caching Screenshots with Rails Cache
Pages that do not change frequently should have their screenshots cached to avoid redundant API calls. Rails.cache integrates directly with your service:
def self.capture_cached(url, ttl: 24.hours)
Rails.cache.fetch("snapshot:#{Digest::MD5.hexdigest(url)}", expires_in: ttl) do
capture(url)
end
end
Use Redis as your cache store for persistent caching across dynos on Heroku. The TTL parameter lets you tune freshness per content type: 24 hours for documentation pages, 1 hour for live dashboards, and 7 days for static marketing pages that rarely change.
Displaying Screenshots in Rails Views
Once you have stored the screenshot binary in ActiveStorage or S3, display it in your Rails views using standard image tags. For inline data URIs during development, base64-encode the binary and embed directly: data:image/png;base64,<%= Base64.strict_encode64(screenshot_data) %>. In production, always serve from CDN using a signed URL from your storage backend. Rails ActiveStorage makes this trivial with rails_blob_url(@record.screenshot).
Full-Page and PDF Exports from Rails
SnapAPI supports full-page screenshot captures and PDF generation from any URL. For Rails applications that need to export reports as PDFs, pass format: "pdf" to the SnapAPI endpoint instead of capturing a screenshot. The response is a binary PDF that you can stream directly to the user with Rails' send_data method or store in ActiveStorage for later download. This replaces complex PDF generation gems like WickedPDF or PDFKit for use cases that involve rendering web pages rather than generating PDFs from templates.
Getting Started
Sign up for a free SnapAPI account at snapapi.pics/dashboard. The free plan includes 200 screenshots per month with no credit card required. Your API key is ready immediately after signup. Read the complete parameter reference at snapapi.pics/docs to explore element selectors, CSS injection, proxy support, and webhook callbacks.