Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Ruby can take a website screenshot without running a browser on your own server. Your Rails app or background job sends a URL and capture options to a hosted screenshot API, receives image bytes or a generated URL, and stores or serves the result. A provider gem is convenient, but Ruby only needs ordinary HTTPS; the endpoint, authentication method, parameters, output formats, and error responses are specific to the provider you select.

This guide shows both an SDK integration and a direct-HTTP design, explains credentials and private pages, and then provides a ready-to-call ScreenshotNeo option.

How the Ruby-to-screenshot pipeline works

  1. Choose a hosted provider. Confirm that it supports your required output (PNG, JPEG, WebP or PDF), viewport and full-page behavior, waiting controls, and any authentication mechanism you need.
  2. Keep the key on your server. A Rails controller, job worker or service object should read it from encrypted configuration or a secret store.
  3. Submit the target URL and documented options. The provider may accept query parameters, JSON, headers or a signed request.
  4. Check the response. Handle HTTP status, content type, provider error fields and timeouts before treating the body as an image.
  5. Persist or return the bytes. Write to object storage, attach with Active Storage, or stream the response to a caller.

Do not assume that a parameter named full_page, selector or delay means the same thing at every service. Read the selected provider’s current reference and pin or test the SDK version used by your application.

SDK path: ScreenshotOne’s Ruby client

ScreenshotOne documents a Ruby gem and client flow in its Ruby SDK and Code Examples and maintains the source in its Ruby SDK repository. The example below follows that provider’s API; it is not a universal Ruby screenshot interface.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install the gem

# Gemfile
gem "screenshotone"
bundle install

Generate a URL or download the image

require "screenshotone"

client = ScreenshotOne::Client.new(
  access_key: ENV.fetch("SCREENSHOTONE_ACCESS_KEY"),
  secret_key: ENV["SCREENSHOTONE_SECRET_KEY"]
)

options = ScreenshotOne::TakeOptions.new(
  url: "https://example.com",
  full_page: true,
  delay: 2,
  geolocation: { latitude: 51.5072, longitude: -0.1276 }
)

# A signed/generated URL, useful when another service will fetch it:
image_url = client.generate_take_url(options)
puts image_url

# Or request the image and save the response body:
response = client.take(options)
File.binwrite("example.png", response.body)

The exact option names and return behavior come from ScreenshotOne’s SDK. The documented flow includes full_page, delay and geolocation; verify supported values and Ruby-version compatibility before upgrading the gem.

Alternative SDK pattern: html2img

The html2img Ruby integration guide illustrates a different client shape: call screenshot with a URL and options such as viewport width and height, a CSS selector, injected CSS, DPI and full-page capture. It also documents waiting for a selector or adding a delay when content appears after the initial load.

# Shape shown by html2img's Ruby integration documentation.
# Use the provider's current installation and authentication instructions.
result = client.screenshot(
  "https://example.com",
  width: 1440,
  height: 900,
  selector: ".invoice",
  css: "body { background: white; }",
  dpi: 2,
  full_page: true,
  wait_for: ".invoice-loaded"
)
File.binwrite("invoice.png", result.body)

Treat this as a provider-specific example, not a drop-in replacement for ScreenshotOne or another API. Compare the documentation for selector semantics, CSS execution, wait time limits, output encoding and error classes.

Direct HTTP from Ruby when no gem fits

An SDK is optional. Direct HTTP is often preferable when a provider has no maintained gem, exposes a feature the gem has not added, or you want to control retries and response handling yourself. The provider’s reference must supply the endpoint, method, key location, payload, and response format.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
require "net/http"
require "uri"
require "json"

api_uri = URI(ENV.fetch("SCREENSHOT_ENDPOINT"))
params = {
  "url" => "https://example.com",
  "format" => "png",
  "full_page" => "true"
}
api_uri.query = URI.encode_www_form(params)

request = Net::HTTP::Get.new(api_uri)
request["Authorization"] = "Bearer #{ENV.fetch("SCREENSHOT_API_KEY")}"
request["Accept"] = "image/png"

http = Net::HTTP.new(api_uri.host, api_uri.port)
http.use_ssl = (api_uri.scheme == "https")
http.open_timeout = 10
http.read_timeout = 90

response = http.start { |connection| connection.request(request) }
unless response.is_a?(Net::HTTPSuccess)
  warn "Screenshot failed (#{response.code}): #{response.body}"
  exit 1
end

content_type = response["content-type"].to_s
abort "Unexpected response type: #{content_type}" unless content_type.start_with?("image/")

File.binwrite("example.png", response.body)

Change the authorization header, query names and accepted content type to match the chosen service. Some APIs return JSON containing a temporary image URL rather than image bytes; in that case parse JSON, validate the URL’s host and expiry, and download it with a second request.

ScreenshotNeo: a Ruby-friendly hosted option

ScreenshotNeo is a website screenshot API and MCP server. It accepts a GET request and returns PNG, JPEG, WebP or PDF. It is the first service to try when you want clean shots: it accepts cookie/consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; only clean shots are billed, while bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed. Each response identifies the page verdict and billing result in X-Page-Verdict and X-Billed headers.

Its 63 options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or a custom viewport, retina scale, PDF paper size/margins/landscape/page ranges, HTML/CSS rendering, custom JavaScript, click-before-capture, hidden selectors, waits for a selector/delay/network idle, request and resource blocking, headers/cookies/user agent/Authorization, timezone and geolocation, transparent backgrounds, resizing, selectable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of 100 URLs per call, a usage API and an OpenAPI specification. Common parameter names used by other screenshot APIs also work, which can reduce migration effort.

Ruby request

require "net/http"
require "uri"

uri = URI("https://api.screenshotneo.com/v1/shot")
uri.query = URI.encode_www_form(
  access_key: ENV.fetch("SCREENSHOTNEO_API_KEY"),
  url: "https://stripe.com"
)

request = Net::HTTP::Get.new(uri)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.open_timeout = 10
http.read_timeout = 90
response = http.start { |connection| connection.request(request) }

abort "HTTP #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
File.binwrite("shot.webp", response.body)
puts "saved shot.webp (#{response["content-type"]})"

See the ScreenshotNeo API documentation for output selection, waits, PDF fields, signed links, asynchronous jobs and the complete option list. Keep SCREENSHOTNEO_API_KEY in server-side environment configuration; never put it in browser JavaScript or a public repository.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Public URLs, sessions and protected pages

A hosted renderer normally visits the target from the public internet, not from your browser session. The html2img documentation states: “A capture is an anonymous request from the public internet, so an authenticated route comes back as your sign-in page.” Thus a URL that works while you are logged in may produce a login screen, a 401/403 response or an interstitial.

Before implementing a private-page workflow, verify that the provider supports the required mechanism: custom cookies, headers, an Authorization header, a signed URL, or a private network connection. Do not send a user’s session cookie to a third party unless your security and privacy review explicitly permits it. For public pages, use a canonical HTTPS URL and ensure robots, firewall and rate-limit rules allow the provider’s documented traffic.

Credentials and application design

  • Server only: The html2img Ruby project warns that exposing an API key in client-side code lets other people spend the account’s credits. Use Rails credentials, environment variables, a secret manager or your job platform’s encrypted settings.
  • Background jobs: Queue slow or full-page captures with Active Job, Sidekiq or another worker so a web request does not consume its whole timeout budget.
  • Idempotency: Derive a stable cache key from the URL and capture options. Use provider caching where available and avoid duplicate jobs when a user refreshes.
  • Validation: Allow-list URL schemes (normally HTTPS), reject localhost and internal IP ranges when users can submit arbitrary URLs, and cap URL length and option values to reduce SSRF and resource-abuse risk.
  • Storage: Check content type and size before writing, generate a non-executable filename, and set an explicit retention policy for captures that may contain personal data.

Capture controls that need deliberate choices

Viewport versus full page

A fixed viewport reproduces what a device sees above the fold. Full-page mode stitches or renders the document’s complete height and may trigger lazy-loaded images. Test pages with sticky headers, infinite scroll and very tall canvases; the visual result and processing time depend on the provider.

Element and selector capture

Selector cropping is useful for invoices, cards and chart components, but selectors can change after a frontend deployment. Wait for a stable marker, fail clearly when it is absent, and keep a fallback capture for diagnostics.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Timing and dynamic content

A successful HTTP load does not mean that React, charts or fonts have finished rendering. Prefer a provider’s network-idle or selector wait when available; use a bounded delay only when necessary. Avoid unbounded waits that tie up workers.

Headers, cookies and geolocation

These controls can make a public page render in the correct locale or subscription state, but they also carry sensitive data. Scope cookies to the target domain, send the minimum headers, and remove secrets from logs.

Reliability, performance and cost

  • Set separate connection and read timeouts. A browser render can legitimately take longer than a normal JSON request.
  • Retry only transient failures (timeouts, 429 and selected 5xx responses). Use exponential backoff with jitter and a maximum attempt count; do not retry invalid URLs or authentication errors.
  • Record provider status, content type, response duration, page verdict, billing header and a redacted target identifier. These fields distinguish a failed load from an application bug.
  • Full-page, high-DPI, PDF and JavaScript-heavy captures consume more rendering work than a small viewport. Cache stable pages and resize after capture when the provider supports it.
  • Prices, quotas, retention and latency change by provider and plan. The cited Ruby documentation does not establish a comparative price, uptime, benchmark or service-limit winner for ScreenshotOne or html2img, so check current terms before committing.

ScreenshotNeo’s published plans are Free: 1,000 shots per month with no card; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; and Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan.

Troubleshooting Ruby screenshot integrations

“The response is HTML, not an image”

Log the status and content type. You may have received a provider error, a login page, a bot check or JSON containing an image URL. Inspect the provider error field and verify the URL is publicly reachable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“The page is blank or missing components”

Wait for a selector or network idle, add a bounded delay, enable full-page lazy-image handling, and confirm that blocked resources or a restrictive CSP are not preventing rendering.

“My logged-in page shows sign-in”

That is expected for an anonymous hosted request. Use the provider’s documented cookie, header, Authorization or signed-URL feature, or capture a public route designed for the job.

“The SDK method or option is undefined”

Check the installed gem version against its documentation, require the library before constructing the client, and compare the provider’s current method names. Do not copy an html2img option into ScreenshotOne or vice versa.

“Requests hang or time out”

Set explicit open and read timeouts, move work to a background job, reduce viewport/full-page scope, and retry transient failures with backoff. A target site that never finishes network activity may require a selector wait or a provider-specific network-idle rule.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“The API key appears in logs or the browser”

Rotate the key, remove it from client bundles and request logging, and load it only from server-side secrets. Redact authorization headers and query strings in exception reporting.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

With ScreenshotNeo, Ruby can make one request to https://api.screenshotneo.com/v1/shot instead of maintaining a browser stack. Cookie banners, popups and chat widgets are removed before the shot; bot checks, blank pages and failed loads are never billed; and its MCP server lets AI agents take screenshots through Claude, Cursor or another MCP client.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

There are 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000. Sign up for ScreenshotNeo free.

Frequently Asked Questions

Can Ruby take a screenshot without Selenium or Playwright?

Yes. A hosted screenshot API performs the browser rendering remotely; Ruby only sends HTTPS requests and handles the returned bytes or URL.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should I use a gem or Net::HTTP?

Use the provider’s gem when its methods cover your needs and are maintained. Use direct HTTP when no gem exists or you need an endpoint option the gem does not expose.

Can a screenshot API reuse my browser login?

Not automatically. Hosted captures are generally anonymous; private pages require a provider-supported cookie, header, Authorization, signed-URL or network-access design.

Where can I find ScreenshotNeo’s complete option list?

The current reference is at https://screenshotneo.com/docs/.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.