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

Replace Selenium Ruby’s deprecated driver_opts, driver_path, and port initializer options with a browser-specific Selenium::WebDriver::Service object. Put the driver executable, driver-process arguments, and port on the service; keep browser switches such as --headless in the browser Options object.

The migration applies the same separation to Chrome, Firefox, and Edge. A minimal Chrome conversion is:

service = Selenium::WebDriver::Service.chrome
service.executable_path = '/path/to/chromedriver'
service.port = 9515
service.args << '--log-level=0'

options = Selenium::WebDriver::Options.chrome
options.add_argument('--headless')

driver = Selenium::WebDriver.for(:chrome, service: service, options: options)

Why Selenium changed the initializer

Selenium Ruby’s changelog marks passing driver_opts, driver_path, and port directly to the driver initializer as deprecated. The replacement is a browser-specific Service class. Selenium’s documentation describes Service classes as responsible for managing the starting and stopping of local drivers.

This is more than a renamed hash key. It separates two processes:

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 driver service: the executable Selenium starts, its listening port, and arguments consumed by the driver process.
  • The browser session: browser capabilities, preferences, and command-line switches supplied through an Options object.

Use service: and options: together when creating the session. Do not move every old option into one object.

Before and after: Chrome

Deprecated initializer

driver = Selenium::WebDriver.for :chrome,
  driver_opts: { args: ['--log-level=0'] },
  driver_path: '/path/to/chromedriver',
  port: 9515

Here, the executable path and port configure the driver process. The args entry is also driver-process configuration in this example, not a browser capability.

Supported Service-based initializer

service = Selenium::WebDriver::Service.chrome
service.executable_path = '/path/to/chromedriver'
service.port = 9515
service.args << '--log-level=0'

options = Selenium::WebDriver::Options.chrome
options.add_argument('--headless')

driver = Selenium::WebDriver.for(:chrome, service: service, options: options)

service.executable_path replaces driver_path; service.port replaces port; and driver-process arguments are added to service.args. The browser’s headless switch remains in options.

Where each old setting goes

Deprecated setting Replacement What it controls
driver_path service.executable_path The local driver executable, when you need to specify it explicitly
port service.port The port on which the local driver service listens
driver_opts driver arguments service.args (or service constructor arguments) Command-line arguments consumed by the driver process
Browser flags such as --headless options.add_argument Arguments passed to the browser session
Browser capabilities and preferences The browser-specific Options object Session capabilities, preferences, and browser behavior

The important diagnostic question is: “Does this switch configure the driver executable, or does it configure the browser?” Driver executable settings belong to Service; browser behavior belongs to Options.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

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

Chrome migration step by step

  1. Create the Service: call Selenium::WebDriver::Service.chrome.
  2. Set an executable only when required: assign the full path to service.executable_path. If your environment already resolves the driver, omit this assignment.
  3. Choose a port when required: assign an available integer to service.port. Omit it when Selenium should choose its normal behavior.
  4. Move driver arguments: append each driver-process argument to service.args.
  5. Create browser options: use Selenium::WebDriver::Options.chrome and add browser switches, preferences, and capabilities there.
  6. Start the session: pass both objects to Selenium::WebDriver.for(:chrome, service: service, options: options).

A reusable Ruby method

require 'selenium-webdriver'

def build_chrome_driver(driver_path: nil, port: nil, headless: false)
  service = Selenium::WebDriver::Service.chrome
  service.executable_path = driver_path if driver_path
  service.port = port if port
  service.args << '--log-level=0'

  options = Selenium::WebDriver::Options.chrome
  options.add_argument('--headless') if headless

  Selenium::WebDriver.for(:chrome, service: service, options: options)
end

driver = build_chrome_driver(
  driver_path: '/path/to/chromedriver',
  port: 9515,
  headless: true
)

begin
  driver.get('https://example.com')
  puts driver.title
ensure
  driver.quit
end

The ensure block matters in test runners and scripts: it closes the browser and lets Selenium stop the local service even when navigation or an assertion fails.

Firefox and Edge equivalents

Firefox

service = Selenium::WebDriver::Service.firefox
service.executable_path = '/path/to/geckodriver'
service.port = 4444
service.args << '--log=debug'

options = Selenium::WebDriver::Options.firefox
options.add_argument('-headless')

driver = Selenium::WebDriver.for(:firefox, service: service, options: options)

Use the Firefox Service factory for the Firefox driver executable. Firefox browser arguments stay on Firefox Options.

Edge

service = Selenium::WebDriver::Service.edge
service.executable_path = '/path/to/msedgedriver'
service.port = 17556
service.args << '--verbose'

options = Selenium::WebDriver::Options.edge
options.add_argument('--headless')

driver = Selenium::WebDriver.for(:edge, service: service, options: options)

Edge follows the same split: Edge driver process settings on the Edge Service, Edge browser settings on Edge Options.

Handling paths, ports, and arguments safely

Executable paths

Use an absolute path when a machine has multiple driver versions or when the driver is not on the process PATH. Verify that the file exists and is executable under the account running the test. A path that works in an interactive shell may fail in CI because the runner uses a different user or environment.

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

Ports

A fixed port is useful when another process must connect to the driver, but it creates a collision risk when tests run in parallel. Give each concurrent process a distinct available port, or omit the assignment if a fixed port is not part of your integration contract. A “port already in use” error is a service-startup problem, not a browser option problem.

Service arguments versus browser arguments

Arguments such as driver logging controls belong in service.args. A switch that changes Chrome, Firefox, or Edge itself belongs in that browser’s Options object. If a browser flag is placed on the Service, the driver may ignore it or reject it because the driver process does not understand browser-only arguments.

Common migration failures and fixes

Deprecation warnings remain

Cause: one code path still passes driver_opts, driver_path, or port to Selenium::WebDriver.for.

Fix: search factories, shared test helpers, and environment-specific branches. Construct the Service in each browser-specific branch and pass it with the service: keyword.

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

“Executable not found” or service cannot start

Cause: service.executable_path points to a missing file, the path is relative to an unexpected working directory, or the runner lacks execute permission.

Fix: use an absolute path, check permissions as the test user, and confirm the driver matches the browser installed in that environment. If automatic driver resolution is configured, remove an obsolete hard-coded path rather than pointing at a stale binary.

“Address already in use”

Cause: another driver or test process owns service.port.

Fix: stop the orphaned process, choose a free port, or avoid hard-coding the port for parallel tests. Ensure every test calls driver.quit in an ensure block.

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

Headless mode is ignored

Cause: --headless was moved to service.args.

Fix: put it on the browser options object, for example options = Selenium::WebDriver::Options.chrome followed by options.add_argument('--headless').

The driver starts but a browser capability has no effect

Cause: a browser preference or capability was treated as a driver-process argument.

Fix: configure it through the relevant Options object. Service is only for managing the local driver process.

Tests pass locally but fail in CI

Cause: differences in installed browser, driver, filesystem path, permissions, user, or available ports.

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

Fix: log the effective environment, use paths visible to the CI account, avoid assumptions about the working directory, and test the chosen port and executable before creating the session. The API shape is documented, but runtime results still depend on the Ruby gem, browser, driver, and local environment versions.

Verification checklist

  • The browser-specific Service factory is used: Chrome, Firefox, or Edge.
  • No deprecated initializer keys remain.
  • driver_path is now service.executable_path, if an explicit path is needed.
  • port is now service.port, if a fixed port is required.
  • Driver-process arguments are on service.args.
  • Browser switches, preferences, and capabilities are on Options.
  • The session call includes both service: service and options: options.
  • The test quits the driver in cleanup code.
  • The target machine’s browser, driver, Ruby gem, path, permissions, and port have been checked.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance, reliability, and parallel-test considerations

Service configuration does not make navigation faster by itself; it controls how the local driver process is launched. Reliability comes from making that launch deterministic: use a known executable when necessary, avoid port collisions, keep browser flags in Options, and always clean up sessions.

For parallel suites, do not give every worker the same fixed port. A worker-specific port or Selenium’s normal port-selection behavior avoids two services competing for one listener. Likewise, avoid a single shared driver executable path that only exists on one workstation; package or provision the driver consistently for every runner.

When diagnosing startup failures, separate the stages: first confirm the Service can launch, then confirm the browser session can be created, and only afterward investigate page navigation or application assertions. This prevents a browser capability problem from being mistaken for a driver executable problem.

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

Or skip the browser setup

If your goal is simply to obtain a clean screenshot or PDF rather than drive an interactive browser, ScreenshotNeo provides a single HTTP request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

See the ScreenshotNeo API documentation for authentication and options. This cURL request captures Stripe as WebP:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

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}`);

Every plan includes full-page capture, element selection, device and viewport controls, retina scale, PDF settings, custom CSS and JavaScript, waits, request blocking, headers, cookies, geolocation, caching, signed links, asynchronous jobs, bulk capture, usage data, and an OpenAPI specification. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.

Frequently Asked Questions

Can I still pass a custom ChromeDriver path?

Yes. Assign the absolute path to service.executable_path on a Chrome Service object, then pass that object with service:.

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

Should every argument from driver_opts move to service.args?

No. Move driver-process arguments to service.args; browser switches, preferences, and capabilities belong in the browser’s Options object.

Do Firefox and Edge use the same migration pattern?

Yes. Use Selenium::WebDriver::Service.firefox or Service.edge, with the corresponding Options object.

Is a fixed port required?

No. Set service.port only when your environment requires a known port. Fixed ports need coordination in parallel runs.

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.