ScreenshotRender
← Back to blog
Tutorials

How to Screenshot a Website in Ruby: 3 Ways

Robert Belt·9 min read
Updated On :
Developer with a laptop and a coffee mug beside the title How to Screenshot a Website in Ruby: 3 Ways on an orange background

Ruby will happily fetch a page, parse the HTML, and render a view of its own, but it cannot paint someone else's page, and a screenshot is paint. By the end of this you'll know the three ways to screenshot a website in Ruby, which one survives production, and how to do it in a single HTTP call when you don't want Chrome anywhere near your server.

The three are Ferrum (the Ruby driver that talks straight to headless Chrome), Selenium WebDriver (the one already sitting in most Rails test suites), and a single HTTP call to a screenshot API with no browser on your server at all. They run from most to least infrastructure to own, and each one fits a different job.

How do you take a screenshot of a website in Ruby?

The shortest path to a screenshot of a website in Ruby is one HTTP request to a screenshot API: send a URL, get back a hosted image, with no browser to install or drive yourself. With ScreenshotRender the whole capture is one line: https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://www.ruby-lang.org&fullPage=true. Fire that from Ruby's standard library and the JSON response carries a hosted image URL at data.screenshot.

If you'd rather keep the rendering on your own machine, the Ferrum and Selenium routes below run a real Chrome locally, at the cost of installing and patching that browser yourself. The rest of this post shows all three, so you can pick by how much infrastructure you want to own.

Why does Ruby need a headless browser to screenshot a website?

Ruby needs a headless browser to screenshot a website because its standard library has no rendering engine, so nothing in Ruby can lay out a page and paint pixels on its own. Ruby can pull the HTML down over Net::HTTP, but turning that HTML into an image means running a real browser engine, and Ruby does not ship one.

That leaves two shapes of local solution and one remote one. You can pull in Ferrum or Selenium, both of which drive a real Chrome, so the browser does the rendering and your Ruby code just sends commands. Or you can hand the whole job to a remote service over HTTP and read back an image URL. The Chrome DevTools Protocol is the common thread underneath all three: Ferrum is a Ruby client for it, Selenium reaches it through a driver process, and a screenshot API runs the same kind of browser on its own hardware.

How do you screenshot a website in Ruby with Ferrum?

You screenshot a website in Ruby with Ferrum by opening a browser, navigating to the URL, and calling the screenshot method with a path. Ferrum is a headless Chrome API for Ruby that speaks the DevTools Protocol directly, with no Selenium, no WebDriver, and no ChromeDriver in the middle, so a full capture is three lines.

Add gem "ferrum" to your Gemfile, then run browser = Ferrum::Browser.new, point it at the page with browser.go_to("https://www.ruby-lang.org"), and write the image out with browser.screenshot(path: "ruby.png", full: true). Call browser.quit when you're done so the Chrome process actually goes away.

The screenshot method is where Ferrum earns its place. Alongside path it takes:

  • full for the entire scrollable document instead of the viewport
  • format for PNG or JPEG output
  • quality for JPEG compression, from 0 to 100
  • selector to capture one element instead of the whole page
  • scale to zoom the capture in or out

Drop full: true and you get the visible viewport only.

What just happened is that Ferrum spoke straight to a Chrome you already have installed and asked it to render the page and write out the bytes. It does not download a browser; it expects to find Chrome or Chromium on the box and in your PATH. That is the catch in production: every server and CI runner that runs this needs a Chrome binary, the right shared libraries, and the fonts the page expects, and you keep all of that patched as Chrome ships a new headless stable.

How do you take a full page screenshot in Ruby with Selenium?

You take a full page screenshot in Ruby with Selenium by calling driver.save_full_page_screenshot("full.png"), and it works on Firefox only. The ordinary save_screenshot call grabs the visible viewport and nothing below the fold, which is the single most common surprise in Selenium screenshots.

The viewport capture is the easy half: driver = Selenium::WebDriver.for :chrome, then driver.navigate.to "https://www.ruby-lang.org", then driver.save_screenshot("page.png"), then driver.quit. Run that against a long article and you get the top of the page, cropped exactly where the window ends.

Firefox is the exception, because geckodriver implemented a non-standard full page command that Selenium exposes to Ruby as save_full_page_screenshot. There is no equivalent on Chrome, Edge, or Safari, so the same code against Chrome raises instead of capturing. If your suite is Chrome-only, the practical fix is to switch that one job to Ferrum, which gets the whole page with full: true on Chrome. The browser-by-browser detail is in our guide to taking a Selenium screenshot.

The deeper cost is process count. Selenium runs your Ruby, plus a driver binary, plus a browser, and all three have to be version-compatible on every machine that runs the job. It is a reasonable trade when the screenshot is one assertion inside a suite you already maintain. It is a lot of moving parts when a screenshot is the only thing you wanted.

Stop installing Chrome next to your Ruby app.

Ferrum and Selenium both run a real Chromium on your server, with the RAM, the driver version pinning, and the bot fights that come with it. ScreenshotRender renders the page for you and returns a hosted image, with cookie banners and ads already stripped. 100 free screenshots, no credit card.

Try a render

How do you screenshot a website in Ruby with a screenshot API?

You screenshot a website in Ruby with a screenshot API by sending the URL to one HTTP endpoint and reading the image URL out of the JSON response, with no browser on your server. The full request is one copy-pasteable line: https://screenshotrender.com/api/v1/screenshot?apiKey=YOUR_API_KEY&url=https://www.ruby-lang.org&fullPage=true.

From Ruby you fire that with the standard library, no gem to add: res = Net::HTTP.get(URI(endpoint)), parse it with JSON.parse(res), and read the hosted image URL from data.screenshot. Your Gemfile stays exactly as long as it was, which is the real difference from the two routes above.

The parameters are the whole surface. url is the page to capture, fullPage=true grabs the entire scrollable document instead of the default 1280 by 720 viewport, wait takes a delay in seconds for pages that finish rendering after the initial load (it defaults to 2 seconds), and timeout caps how long a slow page can take. The response also carries the page title, description, and favicon alongside the image, which is handy if you are building a link preview card in Rails. There is more than one screenshot API and they differ on exactly these defaults, so I broke down how to choose in our guide to the best screenshot API.

The other thing you stop doing is cleanup. Cookie consent banners, ad overlays, and chat widgets are removed automatically before every capture, on every plan including the free one, so the image is the page rather than the page plus three popups. Repeat captures of the same URL and options are served from an edge cache, and you pay only for successful requests, so a failed render does not cost a credit. The free tier is 100 screenshots at 40 requests per minute, with no credit card.

When does Ruby website screenshot capture fail?

Ruby website screenshot capture fails in a few predictable ways, and the cause is rarely the Ruby code itself.

  • Bot protection. A vanilla headless Chrome, whether you drive it with Ferrum or Selenium, gets served a challenge page on bot-protected sites, so the capture is the challenge rather than the site. ScreenshotRender ships Stealth Mode on the Hobby plan and above; our guide to screenshotting Cloudflare-protected sites covers what changes.
  • Lazy loading and JS timing. Content that loads after the first paint, like images that appear on scroll, is missing if you capture too early. A wait for a selector, a short sleep before browser.screenshot, or the API's wait parameter all let the page settle first.
  • Login walls. A URL-only API takes a URL, not a session cookie, so it cannot reach a page behind a sign-in. That is the one case where driving the browser yourself wins, because Ferrum and Selenium can script the login before the shot.
  • Worker memory. Chromium is memory-hungry, and a Puma worker or a small dyno will get killed when several captures run at once. Moving the render off your host removes the whole class of problem, since nothing heavy runs beside your app.

Most failures are timing or access, not the capture itself. Match the fix to the cause and the image comes back clean.

Common questions about taking screenshots in Ruby

How do I take a full page screenshot in Ruby?

Capture the whole scrollable document instead of the visible viewport. With Ferrum you pass full: true to browser.screenshot; with Selenium you call driver.save_full_page_screenshot, which only works on Firefox because geckodriver implemented a non-standard command for it; with a screenshot API you add fullPage=true to the request. The default capture in all three is just the visible viewport. The scroll-and-stitch mechanics underneath are in our guide to screenshotting an entire webpage.

Is Ferrum or Selenium better for Ruby screenshots?

Ferrum is the better fit for screenshots. It talks straight to Chrome over the Chrome DevTools Protocol with no WebDriver in between, so there is one less process to install and version-match, and its screenshot method takes full, format, quality, and selector options directly. Selenium is the better fit when the screenshot is one step inside an existing test suite you already run across multiple browsers, since you keep one tool rather than two.

Do I need to install Chrome to screenshot a website in Ruby?

For the local routes, yes. Ferrum needs Chrome or Chromium on the machine and in your PATH, and Selenium needs both a browser and its matching driver binary. A screenshot API needs no browser on your host at all, since the rendering happens on the service, which is exactly why it works on small dynos and containers where you cannot install system packages.

How do I screenshot a JavaScript-heavy page in Ruby?

Use a real browser and wait for it to settle. Ferrum and Selenium both drive Chrome, so JavaScript executes and modern React, Vue, and Hotwire pages render correctly; add a wait for a selector or a short sleep so lazy-loaded images and late content land before the capture rather than after it. A screenshot API runs Chromium for you and takes a wait parameter in seconds for the same reason.

Can I take a screenshot in Ruby without a headless browser?

Not on your own machine. Ruby has no rendering engine in its standard library, so something has to run a browser to paint the page. Either drive one locally with Ferrum or Selenium, or call a screenshot API that renders remotely, in which case no browser runs on your server and your Ruby code only makes an HTTP request with Net::HTTP.

The honest takeaway: match the method to the machine. On a server you control with Chrome already installed, Ferrum is the thinnest path to a screenshot and the only local route that gets a full page capture on Chrome. If the shot belongs inside a Selenium suite you already run, stay there and accept the Firefox caveat. And to turn any public URL into a clean image without putting a browser next to your Ruby app at all, the single HTTP call is the least to maintain.

Keep reading