ScreenshotNeo

BlogHow-to

Generating Website Screenshots with Ruby: Ferrum, Options, and Production Tips

Capture website screenshots in Ruby with Ferrum, from a runnable quick start to full-page images, PDFs, troubleshooting, and a browser-free API option.

By the ScreenshotNeo team29 September 20269 min read

Generating Website Screenshots with Ruby: Ferrum, Options, and Production Tips

To generate a website screenshot with Ruby, use Ferrum, which drives Chrome or Chromium through the Chrome DevTools Protocol (CDP). Install the gem, make a browser, navigate to a URL, save a screenshot, and always close the browser. Ferrum runs headlessly by default and does not depend on Selenium, WebDriver, or ChromeDriver. [Ferrum project documentation]

require "ferrum"

browser = Ferrum::Browser.new
begin
  browser.go_to("https://example.com")
  browser.screenshot(path: "example.png")
ensure
  browser.quit
end

This captures the current viewport as PNG. For repeatable captures, configure the browser executable and viewport, wait for the page state your target needs, and choose viewport, full-page, element, or rectangular-area capture deliberately. This guide covers those choices and their operational tradeoffs, then shows a hosted alternative if installing and maintaining a browser is not part of your Ruby application’s job.

1. Install Ruby, Ferrum, and Chrome or Chromium

Ferrum is a Ruby interface to Chrome and Chromium. The browser executable must be available on PATH or supplied with Ferrum’s browser-path configuration. Follow the Ferrum documentation for its current installation instructions and obtain Chrome or Chromium from an official source; this research does not establish a version compatibility matrix, so verify versions in your own deployment environment. [Ferrum documentation]

Add Ferrum to an existing Bundler project:

# Gemfile
gem "ferrum"
bundle install

Or install the gem directly for a small script:

gem install ferrum

Then check that Ruby can load it and that the browser is present in the execution environment. Installing the gem does not itself install Chrome/Chromium. That distinction matters in containers, CI workers, and production hosts: the Ruby dependency can resolve successfully while browser startup still fails because the executable or its runtime dependencies are missing.

2. Make a screenshot from a Ruby script

This complete script accepts the destination URL as an argument, saves a PNG to a chosen path, and closes Chrome even if navigation or capture raises an exception.

A Ruby capture flow: navigate with Ferrum, render in Chrome or Chromium, and save the resulting image.
A Ruby capture flow: navigate with Ferrum, render in Chrome or Chromium, and save the resulting image.
#!/usr/bin/env ruby
require "ferrum"

url = ARGV.fetch(0, "https://example.com")
output = ARGV.fetch(1, "page.png")
browser = Ferrum::Browser.new

begin
  browser.go_to(url)
  browser.screenshot(path: output)
  puts "Saved #{output}"
ensure
  browser.quit
end
ruby screenshot.rb https://example.com example.png

The browser-level screenshot shown here is Ferrum’s documented quick-start form. In an application that manages pages explicitly, create a page and call page.screenshot(...); Ferrum’s documentation describes the page object as the way to interact with a manually created page. The page-oriented form is useful when a workflow needs to set page state or manage more than one page. Keep browser cleanup in an ensure block in either style. [Ferrum documentation]

require "ferrum"

browser = Ferrum::Browser.new
begin
  page = browser.create_page
  page.go_to("https://example.com")
  page.screenshot(path: "example.png")
ensure
  browser.quit
end

Use a fresh browser or page context when captures should not share cookies or other session state. Conversely, a deliberately reused session can be useful when a site requires authentication, but be explicit about which cookies and state are carried between URLs. Close the browser after a batch; leaving browser processes behind can consume memory and cause later jobs to fail.

3. Choose the capture scope and output format

Ferrum documents viewport capture as the default, plus full-page capture, CSS-selector capture, and a specified rectangular area. Screenshots can be written to a file or returned as base64. Supported image formats are PNG, JPEG/JPG, and WebP; PNG is the default, and JPEG or WebP accept quality settings. Ferrum also supports PDF export, including paper size and orientation options. Consult its screenshot API reference for exact option names and current behavior. [Ferrum screenshot documentation]

Need Capture choice Practical consideration
What a visitor currently sees without scrolling Viewport Set a consistent viewport when comparing pages or generating predictable cards.
The complete long page Full page Large pages may produce tall, memory-intensive images; inspect the output dimensions.
One component or chart CSS selector Wait until the target exists and is rendered; a missing or hidden element cannot yield the intended crop.
A known screen region Rectangular area Coordinates depend on viewport size and layout, so responsive changes can shift the target.
Lossless output or sharp text PNG Default format; commonly suitable for documentation and visual checks.
Smaller photographic output JPEG or WebP with quality Choose quality for the use case and check that compression artifacts are acceptable.
Printable document PDF Set paper dimensions and orientation for the intended page; PDF layout is distinct from a viewport image.

The formats and options are documented capabilities, not a guarantee that every site will render identically. Fonts, animations, dynamic content, consent overlays, and responsive breakpoints can change between runs. No comparative timing, fidelity, or file-size benchmark is established here.

# Viewport PNG (default)
browser.screenshot(path: "viewport.png")

# Full page
browser.screenshot(path: "whole-page.png", full: true)

# Selector capture: verify exact option names against the installed
# Ferrum documentation for your version.
browser.screenshot(path: "card.png", selector: ".product-card")

Ferrum’s API has several capture modes and output controls; refer to the project documentation for the accepted option spelling for your installed release. The examples above illustrate the common interface shape, but pinning a gem version and checking its matching documentation is important when capture options form part of a production contract.

4. Make captures repeatable

A screenshot taken immediately after navigation may catch a loading state, a late-loading image, or an animation frame. Decide what “ready” means for the target page. For a static page, navigation completion may be sufficient. For an application, wait for a page-specific selector or other known condition using Ferrum’s page interaction and waiting facilities. Avoid relying only on a long arbitrary sleep: it adds latency to every capture and still cannot guarantee that a slow page is ready.

  1. Use a fixed viewport for repeatable layout.
  2. Navigate to the exact URL, including query parameters that affect state.
  3. Wait for a meaningful page condition, such as the element to capture becoming visible.
  4. Disable or account for animation when pixel stability matters.
  5. Capture and inspect dimensions, output format, and any expected content.
  6. Close the browser in all success and failure paths.

Web pages are not static documents. A page can return a successful navigation while still displaying a client-side error, a consent prompt, a bot check, or empty content. If the screenshot is part of a monitoring or publishing pipeline, validate the result against application-specific expectations instead of assuming every image file represents a useful page.

5. Run Ferrum in a service, job, or test suite

For a one-off script, one browser per run is straightforward. For a background worker, balance browser startup overhead against isolation: reusing a browser can avoid repeated launches, while separate contexts or browser instances can keep sessions isolated. The appropriate choice depends on your workload; the dossier contains no performance benchmark. Put a timeout around the job at the worker or process level, limit concurrent browser processes to available memory, and close pages and browsers after exceptions.

For Capybara test suites, Ferrum identifies Cuprite as a pure Ruby Capybara driver based on Ferrum. That route is appropriate when screenshots are tied to browser-driven test flows; use Ferrum directly for a script or service that simply navigates and captures. [Ferrum documentation]

In containers and CI, make the browser executable path an explicit deployment setting when it is not on PATH. Confirm that the runtime image includes Chrome/Chromium and the operating-system libraries it needs. Do not assume that a browser available on a developer laptop is also present in a slim production image. Keep browser output and error logs available so startup and navigation failures can be distinguished.

6. Troubleshoot common failures

Symptom Likely cause What to check or change
Browser executable not found Chrome/Chromium is absent or outside PATH. Install the browser from an official source or configure Ferrum with the executable path.
Browser starts locally but not in CI/container The deployment image lacks the browser or one of its runtime requirements. Check the image contents and browser startup logs; configure the path in that environment.
Navigation times out The site is slow, waiting on long-lived network activity, or unreachable from the runner. Check URL and network access, choose a suitable navigation/wait condition, and set a bounded job timeout.
Screenshot is blank or shows a spinner Capture happened before the app rendered, or navigation landed on an error/check page. Wait for the page’s real content and inspect the resulting page state before accepting the file.
Target element is missing Selector changed, element is late, hidden, or in a different document context. Verify the selector against the rendered page and wait for the element before capture.
Full-page image is unexpectedly huge The page has long content or expanding elements. Use viewport or element capture when that matches the requirement; validate dimensions and memory use.
Capture output differs between runs Dynamic content, responsive layout, fonts, animation, or session state changed. Fix viewport and session inputs, wait on stable content, and account for animated or personalized regions.
Browser processes accumulate Cleanup is skipped after an exception or in a worker shutdown path. Put browser.quit in ensure and test cleanup on error paths.

Ferrum communicates with the browser over CDP and does not require Selenium, WebDriver, or ChromeDriver. That removes those particular components from the setup, but it does not remove the need to install and operate Chrome or Chromium. [Ferrum project documentation]

7. Performance, reliability, and cost considerations

With Ferrum, you operate the browser environment: provisioning Chrome/Chromium, allocating CPU and memory, setting concurrency, and deciding how to handle timeouts and retries. Full-page captures and multiple simultaneous browsers can increase resource demand; measure your own pages and deployment rather than relying on an undocumented generic benchmark. A retry can help with transient network failures, but retry only bounded failures and avoid multiplying load against a slow destination.

The software cost of this approach includes your time maintaining the Ruby gem and browser runtime, plus the compute resources where captures run. This dossier does not provide package pricing or a deployment cost comparison. For reliability, record the URL, capture mode, elapsed job outcome, and error class in your own logs; avoid logging credentials or sensitive query parameters. Treat a screenshot as successful only after checking that the response/file exists and the expected page content was captured.

8. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server for developers. A single GET request returns a screenshot or PDF, so a Ruby application can request an image without installing Chrome locally. The call below follows its documented API pattern; see the ScreenshotNeo API documentation for options and details.

A hosted capture can remove common overlays before returning the screenshot.
A hosted capture can remove common overlays before returning the screenshot.
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}`);

For Ruby, pass the same query parameters to your HTTP client and save the response body as a file. Store the API key in an environment variable or secret manager rather than committing it to source control.

  • Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off.
  • Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers say which verdict applied and whether the request was billed.
  • An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and any MCP client.
  • The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is on every plan.

ScreenshotNeo is useful when you want an API call instead of maintaining the browser installation and capture worker yourself. Create a free account for 1,000 screenshots a month with no card.

9. FAQ

Can Ferrum run without a visible browser window?

Yes. Ferrum runs headlessly by default, according to its project documentation. [Ferrum documentation]

Do I need Selenium or ChromeDriver with Ferrum?

No. Ferrum’s documentation says it connects through CDP and has no Selenium, WebDriver, or ChromeDriver dependency. You still need Chrome or Chromium available. [Ferrum documentation]

Can I return image data instead of writing a file?

Ferrum documents returning screenshot data as base64 as well as saving to a path. Choose the form that fits your application’s storage or response pipeline. [Ferrum screenshot documentation]

Should I use Ferrum or Cuprite?

Use Ferrum directly for a Ruby script or capture service. If the work belongs to a Capybara test suite, Cuprite is the Capybara driver based on Ferrum identified by the project documentation. [Ferrum documentation]

Does a successful screenshot prove the site is healthy?

No. A file can be produced from a bot challenge, application error, or incomplete page. Validate the captured content against the condition that matters to your workflow.