What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Set the timeout for the operation that can stall, not for “screenshots” as one universal task. In a Ruby browser script, navigation, JavaScript waits, remote-driver communication, element lookup and image capture have separate limits. With Ferrum, configure a page-level command timeout and, when needed, pass a shorter timeout to screenshot. With Selenium, set page_load for navigation and configure the Ruby HTTP client’s read timeout when a remote driver connection is the slow part.
The examples below keep navigation, readiness checks and capture as distinct steps so a slow page fails predictably instead of leaving a process hanging.
What a screenshot timeout actually controls
A screenshot workflow normally has four stages:
- Navigation: the browser requests the URL and follows redirects.
- Readiness: your application waits for a selector, a state change or a known delay.
- Capture preparation: the browser may resolve a CSS selector, calculate bounds or load lazy content.
- Image transfer: the driver returns PNG, JPEG or another encoding to Ruby and Ruby writes it to disk.
A page-load timeout bounds the first stage. It does not prove that a single-page application has finished rendering, and it does not necessarily bound the time needed to find an element or transfer the screenshot. Treat each stage as a separate failure point and rescue the exception appropriate to the library you use.
Ferrum: bound navigation and screenshot commands
Ferrum is “a high-level API to control Chrome in Ruby,” according to the Ferrum project documentation maintained by rubycdp. Its quick-start flow is a navigation followed by a screenshot:
#1 Best Overall
browser = Ferrum::Browser.new
browser.go_to("https://example.com")
browser.screenshot(path: "example.png")
browser.quit
Ferrum uses a page command timeout for browser operations. The default is the page timeout, and individual callers such as screenshot and PDF can receive a command-level override. Constructor option names and defaults can vary by the gem version pinned in your lockfile, so confirm them in that installed version’s API before copying an initializer into production.
A version-conscious Ferrum pattern
Keep the timeout value in one place, pass a capture-specific override when your version supports it, and always close the browser:
require "ferrum"
NAVIGATION_TIMEOUT = 30
CAPTURE_TIMEOUT = 15
browser = Ferrum::Browser.new(timeout: NAVIGATION_TIMEOUT)
begin
browser.go_to("https://example.com")
# Replace this with a condition that represents readiness for your page.
browser.at_css("body")
browser.screenshot(
path: "example.png",
timeout: CAPTURE_TIMEOUT,
full: true,
format: "png"
)
rescue Ferrum::TimeoutError => e
warn "Browser operation timed out: #{e.message}"
exit 1
ensure
browser.quit
end
If your installed Ferrum release does not accept timeout: on screenshot, remove that keyword and rely on the page-level timeout after checking the method signature for your version. Do not assume a timeout argument added in one release exists in another.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Wait for the page state you need
A successful navigation can still leave an application rendering data. Prefer a page-specific readiness condition over an arbitrary sleep:
browser.go_to("https://example.com/dashboard")
browser.at_css("[data-page-ready='true']", timeout: 20)
browser.screenshot(path: "dashboard.png", timeout: 15)
For a selector capture, Ferrum must resolve the element and calculate its bounds before encoding the image. That lookup is another operation that can consume the page timeout. Use a stable selector and make the selector timeout long enough for the application to render, but short enough to expose a broken page.
Rank #2
Useful Ferrum capture options
Ferrum’s screenshot API supports viewport and full-page capture, selector or area capture, output path and encoding, image format, quality, scale and background settings. A full-page shot can trigger lazy-image loading; a selector shot adds element-bound calculation. For example:
browser.screenshot(
path: "hero.webp",
format: "webp",
quality: 85,
scale: 2,
selector: ".hero",
background: true
)
Use only options supported by your installed gem version. If a capture times out, first test a viewport screenshot without a selector or full-page mode. That isolates page rendering from bounds calculation and lazy-content work.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Selenium Ruby: separate page-load and transport timeouts
Selenium exposes a page-load timeout in seconds. This documented pattern limits navigation, then saves the current browser view:
require "selenium-webdriver"
driver = Selenium::WebDriver.for :chrome
begin
driver.manage.timeouts.page_load = 30
driver.navigate.to("https://example.com")
driver.save_screenshot("example.png")
ensure
driver.quit
end
page_load is a navigation bound, not a universal deadline for the screenshot operation. Selenium also exposes a separate asynchronous-script timeout for calls such as execute_async_script:
driver.manage.timeouts.script = 10
driver.execute_async_script(<<~JS)
const done = arguments[arguments.length - 1];
Promise.resolve(window.appReady === true).then(done);
JS
For a remote driver, the Ruby binding has a distinct HTTP-client read timeout. Configure that client before creating the driver, using the API exposed by the Selenium version in your bundle. This protects the Ruby-to-driver transport when the browser is reachable but a command response is delayed; it does not replace page_load or an application readiness condition.
Rank #3
A Selenium readiness and capture sequence
require "selenium-webdriver"
driver = Selenium::WebDriver.for :chrome
begin
driver.manage.timeouts.page_load = 30
driver.manage.timeouts.script = 10
driver.navigate.to("https://example.com/app")
wait = Selenium::WebDriver::Wait.new(timeout: 20)
wait.until { driver.find_element(css: "[data-page-ready='true']").displayed? }
driver.save_screenshot("app.png")
rescue Selenium::WebDriver::Error::TimeOutError => e
warn "Selenium operation timed out: #{e.message}"
exit 1
ensure
driver.quit
end
The explicit wait checks an application condition after navigation. If the selector never appears, the wait fails independently of the page-load limit, making the cause easier to diagnose.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteChoosing values without creating false guarantees
There is no documented universal timeout that fits every site, driver and network. Choose values from the slowest legitimate case your service must support, then leave headroom for capture and cleanup.
- Navigation: include DNS, TLS, redirects and server response time.
- Readiness: include the client-side request and rendering needed for the specific screenshot.
- Capture: allow extra time for full-page layout, lazy images, selector lookup and image encoding.
- Transport: for a remote driver, allow the command response to cross the network without masking a dead session.
Keep the limits finite and log which stage failed. A single large timeout hides whether the site, browser, driver or output path is responsible.
Common timeout failures and fixes
Navigation times out, but the page works in a normal browser
Check redirects, authentication, geolocation and bot checks. Confirm that the URL is reachable from the machine running Chrome, then raise only the navigation limit if the extra delay is expected. If the page requires a post-load API call, keep navigation bounded and add a readiness wait instead of making navigation unlimited.
The selector wait or selector screenshot times out
Verify the selector in DevTools and check whether the element is inside an iframe or shadow DOM. Capture the viewport without selector to determine whether the page rendered. For dynamic lists, wait for a stable marker rather than the first transient element.
Rank #4
Full-page capture is slow or incomplete
Full-page mode can force layout work and lazy-image loading. Try a normal viewport capture, then disable nonessential animations with page CSS, or wait for images to finish loading. If the page is extremely long, capture a bounded element or split the job into sections.
Selenium raises an HTTP or connection timeout
This usually concerns communication with a remote driver, not page loading. Check the driver service, network route and the Ruby HTTP client's read-timeout setting. A larger page-load timeout will not repair a transport that cannot return a command response.
The screenshot file is missing or corrupt
Ensure the destination directory exists and the Ruby process can write to it. Use an absolute path while debugging. If the driver reports success but the file is empty, check disk space and capture a simple viewport PNG before testing WebP, high scale or full-page options.
The browser remains running after an error
Put quit in an ensure block. Leaked Chrome processes consume memory and can make later jobs appear to time out even when the website is healthy.
Recommended Free Tools
Reliability and performance practices
- Pin Ferrum, Selenium, Chrome and the driver versions in deployment; verify timeout method signatures after upgrades.
- Record URL, stage, elapsed time, exception class and browser/driver version for every failure.
- Use a bounded retry only for transient network or driver errors. Repeating a deterministic selector failure wastes capacity.
- Prefer one browser session per controlled batch, but restart after crashes or memory growth.
- Disable unnecessary resources only when the screenshot does not depend on them; blocking fonts, scripts or images can change layout.
- For parallel jobs, cap concurrency to the CPU and memory available for Chrome. More workers can increase, rather than reduce, capture latency.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. One request returns a PNG, JPEG, WebP or PDF, so your Ruby service does not need to manage Chrome, Ferrum or Selenium:
Best Value
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for request options and response details. The service can accept consent banners before capture and remove more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and whether the shot was billed. An MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan. Create an account at ScreenshotNeo's free sign-up page.
Ruby, Python and Node.js calls to the same API
If a non-Ruby service owns the job, these equivalent requests use the same endpoint:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errors# Ruby
require "requests" # Use your preferred HTTP client in production
# Python
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)
// Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
In Ruby, use a maintained HTTP client such as Net::HTTP or Faraday to issue the GET and write the response body in binary mode. Set the client timeout to cover the API request, and inspect the returned X-Page-Verdict and X-Billed headers when deciding whether to retry.
Ferrum or Selenium: which timeout model fits?
| Need | Ferrum | Selenium Ruby |
|---|---|---|
| Browser stack | Direct Ruby API for Chrome | WebDriver-controlled browser and driver service |
| Navigation bound | Page command timeout | manage.timeouts.page_load |
| JavaScript wait | Use a page-specific condition supported by your version | manage.timeouts.script plus an explicit wait |
| Remote transport | Depends on the Ferrum/Chrome connection configuration | Ruby HTTP-client read timeout is separate |
| Capture modes | Viewport, full page, selector and area options | save_screenshot of the current browser view; other modes depend on driver/browser support |
Choose the library already integrated with your project, then bind the operation that is actually stalling. Timeout numbers are not interchangeable between these layers.
Frequently Asked Questions
Does setting Selenium's page-load timeout stop a screenshot that hangs?
No. It bounds navigation. Add an explicit readiness wait and investigate the driver or HTTP-client timeout if the capture command itself is delayed.
Should I use a fixed sleep before every Ruby screenshot?
Usually not. Wait for a page-specific selector or state so fast pages finish quickly and slow pages fail for a meaningful reason.
Why can a Ferrum selector screenshot time out when a viewport screenshot succeeds?
Selector mode must find the element and calculate its bounds. A missing, hidden or late-rendered element can fail even though the document itself is available.
Quick Recap
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.

