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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Replace the deprecated initializer keys with a browser-specific Service object. Put the driver executable path in service.executable_path, the listening port in service.port, and driver-process arguments in service.args. Keep browser switches such as --headless in a browser Options object, then pass both objects to Selenium::WebDriver.for.

The migration in one view

Older Selenium Ruby code often puts several unrelated settings directly in the driver initializer:

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

That shape is deprecated. The supported arrangement separates the local driver process from the browser session:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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)

The distinction matters: a Service manages starting and stopping the local driver, while Options describes the browser session. The Selenium Ruby changelog specifically deprecates passing driver_opts, driver_path, and port to the initializer and directs users to browser-specific Service classes.

What each deprecated value becomes

Deprecated initializer value Replacement What it controls
driver_path service.executable_path The local driver executable, when you need to select an explicit file.
port service.port The port used by the local driver service.
driver_opts: { args: [...] } service.args Command-line arguments consumed by the driver process.
Browser arguments such as --headless options.add_argument Command-line switches sent to Chrome, Firefox, or Edge.

Do not mechanically move every argument into service.args. Driver-process arguments belong to the Service; browser flags, capabilities, and preferences belong to Options.

Step-by-step Chrome migration

1. Create the Chrome Service

Use the browser-specific factory:

service = Selenium::WebDriver::Service.chrome

This creates the object Selenium uses to manage the Chrome driver process.

2. Move the executable path, if required

Replace the old driver_path key with an assignment on the Service:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
service.executable_path = '/path/to/chromedriver'

Use a path that exists and is executable in the environment where the Ruby process runs. If your application does not need to select a particular executable, leave this assignment out rather than retaining a stale path.

3. Move the port

service.port = 9515

A fixed port is useful when another part of your environment expects one, but it can collide with an existing process. If you set it, make sure the port is available for every parallel worker that uses it.

4. Move driver-process arguments

service.args << '--log-level=0'

These arguments affect the driver service, not the browser window. Add each argument deliberately; an argument that is meaningful to Chrome itself should instead be added to Chrome Options.

5. Keep browser settings in Options

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

Headless mode is a browser setting, so it remains in options. The same object is where you keep browser capabilities and preferences.

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

6. Start the session with both objects

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

The keyword names are significant: use service: for the Service object and options: for the browser Options object.

A complete, runnable Chrome example

The following example shows all three migrated values and a browser argument in the correct locations:

require 'selenium-webdriver'

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
)

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

Replace the executable path and target URL for your environment. The ensure block closes the browser even when navigation or an assertion raises an exception.

Firefox and Edge use the same separation

The factory changes with the browser, but the migration model does not.

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

Firefox

service = Selenium::WebDriver::Service.firefox
service.executable_path = '/path/to/geckodriver'
service.port = 9516

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

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

Edge

service = Selenium::WebDriver::Service.edge
service.executable_path = 'C:\path\to\msedgedriver.exe'
service.port = 9517

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

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

Chrome uses Service.chrome, Firefox uses Service.firefox, and Edge uses Service.edge. Match the executable to the browser and operating system installed on the machine.

How to classify an existing argument

When modernizing a large test suite, classify each old setting before moving it:

  • Driver executable selection: assign service.executable_path.
  • Driver listening port: assign service.port.
  • Driver logging or service switches: append to service.args.
  • Browser command-line switches: call options.add_argument.
  • Browser capabilities or preferences: configure the browser Options object.

If you cannot tell which process consumes an argument, consult the documentation for that specific driver option rather than placing it in both objects. Duplicating a switch can produce confusing startup failures.

Common migration failures and fixes

“Unknown keyword” or deprecation warnings remain

Cause: one of driver_opts, driver_path, or port is still being passed to Selenium::WebDriver.for.

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

Fix: remove those initializer keys and pass only service: and options:. Search helper methods and factory wrappers as well as individual tests.

The browser flag has no effect

Cause: a browser flag was appended to service.args, where the browser never receives it.

Fix: move the flag to the matching Options object, for example options.add_argument('--headless') for Chrome.

The driver executable cannot be started

Cause: service.executable_path points to a missing, non-executable, or wrong-platform file.

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.

Fix: verify the absolute path, file permissions, and that the executable matches the selected browser. Remove the explicit assignment if the environment supplies the correct driver another way.

The requested port is already in use

Cause: another driver process, test worker, or service owns the port.

Fix: choose an unused port and ensure parallel workers do not all set the same fixed value. A fixed port should be an intentional infrastructure choice, not a copied legacy default.

The session starts, but the test still fails

Cause: the migration changed process startup but not the browser capabilities, preferences, URL, or test assumptions.

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

Fix: isolate startup from test logic: first launch a minimal session, navigate to a known page, and print the title. Then restore application-specific Options and assertions one at a time.

Cleanup is unreliable

Cause: the test exits before quit runs.

Fix: wrap the session in begin ... ensure ... driver.quit ... end, as in the complete example. Service classes manage starting and stopping the local driver, but your test should still close the WebDriver session explicitly.

Verification checklist before committing the change

  1. Confirm the Selenium Ruby gem version used by the target project supports the Service API shown here.
  2. Confirm the browser-specific factory matches the browser under test.
  3. Check that every explicit executable path exists on the target machine.
  4. Check that a fixed port is available and unique where parallel execution is used.
  5. Review every former driver_opts argument and classify it as a Service or browser Option.
  6. Start a minimal session and navigate to a known URL.
  7. Run the full suite in the same operating-system and browser environment used by CI.
  8. Remove obsolete initializer keys so future gem upgrades do not depend on deprecated behavior.

The API documentation establishes the object layout; successful runtime behavior still depends on the installed Ruby gem, browser, driver executable, operating system, and local configuration.

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

Performance, reliability, and parallel runs

The Service migration does not make a browser session inherently faster. Its practical benefit is clearer ownership of startup settings, which makes failures easier to diagnose and configuration easier to vary per browser or worker. For parallel runs, avoid sharing one fixed port between services. Give each worker an available port and an executable environment it can access. Keep browser arguments in Options so changing headless or display behavior does not accidentally alter driver-process startup.

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.

For repeatable builds, keep the Service and Options construction close to the code that owns the session, or expose a small factory that accepts the executable path, port, and browser settings as explicit parameters. This prevents hidden defaults from reintroducing deprecated initializer keys.

Or skip the browser setup

If your goal is a static image or PDF rather than an interactive WebDriver session, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed as clean shots, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—let Claude, Cursor, or another MCP client request captures.

See the ScreenshotNeo API documentation for parameters. This is a complete cURL call:

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

Equivalent 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)

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

ScreenshotNeo includes full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, click-before-capture actions, selector waits, delays or network-idle waits, request and resource blocking, custom headers, cookies, user agents and authorization, timezone and geolocation, transparent backgrounds, resizing, configurable caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, a usage API, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, which can simplify a switch.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Plan Allowance Price
Free 1,000 shots/month No card required
Starter 3,000 shots $5
Growth 15,000 shots $15
Pro 60,000 shots $39
Scale 250,000 shots $99
Business 1,000,000 shots $249

Every feature is included on every plan, and yearly billing provides two months free. Create a free ScreenshotNeo account to get 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots.

Frequently Asked Questions

Do I put Chrome’s `–headless` switch in `service.args`?

No. Put browser switches in the Chrome Options object with `options.add_argument`; reserve `service.args` for driver-process arguments.

Is `service.executable_path` mandatory?

No. Set it only when you need an explicit driver executable. Otherwise omit the assignment and let the environment’s normal driver resolution apply.

Can one Service object be reused by several drivers?

Create and configure a Service for the session that owns it. Reusing a fixed port across concurrent sessions can cause collisions.

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

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.