Selenium Still Matters. Here Is Where Steel Fits.

Keep the Selenium tests, page objects, and reporting stack you trust. Swap the grid underneath with Steel sessions that start in under a second, run up to 24 hours, and record every run so failures come with evidence. You still call `webdriver.Remote`; Steel just hosts the browser, manages lifecycle, and gives you replay URLs tied to each `sessionId`.

Keep the Selenium tests, page objects, and reporting stack you trust. Swap the grid underneath with Steel sessions that start in under a second, run from minutes to hours (up to 24 hours on Enterprise), and record every run so failures come with evidence. You still call webdriver.Remote; Steel just hosts the browser, manages lifecycle, and gives you replay URLs tied to each sessionId.

Steel is not trying to replace WebDriver. It supplies the managed browser runtime when your language mix or compliance rules mean Selenium is staying put. That means a custom connection class for Steel headers, explicit session creation with is_selenium: true, and predictable release calls once the driver quits.

What stays the same

  • selenium.webdriver API surface, from capabilities to waits.
  • Test harnesses: pytest, JUnit, NUnit, or bespoke runners.
  • Page objects, selectors, and assertion utilities.
  • CI wiring: you still export STEEL_API_KEY, set env specific URLs, and fan out suites the same way.
  • Local debugging: you can run against Chrome on your laptop until you point the job at Steel.

What Steel adds

JobDIY grid or localhostSelenium on Steel
StartupWait for EC2 or an on-prem VM to warm ChromeSteel Cloud sessions start in under a second on average — ~0.18s for session creation, ~0.89s end-to-end per Steel's own benchmark — and hand you a ready endpoint
Session lengthBrowsers restart frequently to keep hosts cleanSteel sessions run up to your plan ceiling (15 min Launch · 1 hr Scale · up to 24 hr Enterprise); set timeout explicitly for long flows
EvidenceConsole logs and screenshots if you wired them yourselfEach sessionId maps to logs plus replay exports so failures are reviewable and shareable
Anti-botPatchy proxy rotation and brittle stealth flagsSteel Cloud supplies managed proxies, fingerprints, and CAPTCHA solving — set on the is_selenium session just like Playwright/Puppeteer
Scale & opsMaintain Selenium Grid, Docker images, shared storageSteel handles fleet health; you just connect and release

Minimal integration path

  1. Install the SDK (pip install steel-sdk selenium) so you can create and release sessions explicitly.
  2. Create a session for Selenium:
    session = client.sessions.create(is_selenium=True, persist_profile=True, timeout=3600000)
  3. Wrap Selenium’s RemoteConnection to add Steel headers:
    • steel-api-key: proves you can attach to the session
    • session-id: routes the WebDriver calls to the browser Steel already provisioned
  4. Connect your existing test with webdriver.Remote(command_executor=CustomRemoteConnection(...), options=webdriver.ChromeOptions()).
  5. Release sessions on exit using client.sessions.release(session.id) or client.sessions.release_all() in a finally block so concurrency slots free up fast.

Example code (Python)

import os
from selenium import webdriver
from selenium.webdriver.remote.remote_connection import RemoteConnection
from steel import Steel

STEEL_WS = "http://connect.steelbrowser.com/selenium"
client = Steel(steel_api_key=os.environ["STEEL_API_KEY"])

class SteelRemote(RemoteConnection):
    def __init__(self, url: str, session_id: str):
        super().__init__(url)
        self._session_id = session_id

    def get_remote_connection_headers(self, parsed_url, keep_alive=False):
        headers = super().get_remote_connection_headers(parsed_url, keep_alive)
        headers.update({
            "steel-api-key": os.environ["STEEL_API_KEY"],
            "session-id": self._session_id,
        })
        return headers

def run(url: str):
    session = client.sessions.create(is_selenium=True, persist_profile=True)
    driver = webdriver.Remote(
        command_executor=SteelRemote(STEEL_WS, session.id),
        options=webdriver.ChromeOptions(),
    )

    try:
        driver.get(url)
        # ... your assertions ...
    finally:
        driver.quit()
        client.sessions.release(session.id)
        details = client.sessions.retrieve(session.id)
        print("Replay:", details.session_viewer_url)

if __name__ == "__main__":
    run("https://news.ycombinator.com")

Where Steel fits vs Selenium Grid

ScenarioKeep Selenium GridMove to Steel
Language coverage across Python, Java, C#, RubyAlready works locally; no managed runtime neededSame story, just point WebDriver at Steel and stop tending grid nodes
Long authenticated flows that time out mid runSessions restart unless you hand roll persistenceSteel sessions run up to your plan ceiling (15 min Launch · 1 hr Scale · up to 24 hr Enterprise) and can persist profiles up to 300 MB
Compliance and audit pressureEvidence depends on homegrown loggingSteel records every run and keeps replay URLs plus Agent Traces per session
Anti-bot escalationDIY scripts juggling proxies and CAPTCHA pluginsSteel handles proxies (use_proxy), CAPTCHA solving (solve_captcha), and stealth (stealth_config) on the is_selenium session itself, no extra Selenium-side plugins
Burst scaling for nightly suitesAdd more servers or wait in queueReserve higher Steel Cloud tiers — up to 100 concurrent sessions on Scale, 1,000+ on Enterprise

Trade-offs and guardrails

  • Steel's Selenium integration supports the same session-level capabilities as Playwright and Puppeteer. Proxies (use_proxy), CAPTCHA solving (solve_captcha), and stealth (stealth_config) are configured when you create the session with sessions.create(is_selenium=True), so the Selenium driver doesn't need to know about them. The genuine Selenium-specific trade-off is protocol and latency: Selenium speaks the W3C WebDriver protocol over HTTP rather than CDP, so each command is an HTTP round-trip — prefer WebDriverWait over time.sleep.
  • Max session time is tiered — see Pricing/Limits (15 min Launch · 1 hr Scale · up to 24 hr Enterprise; default 5 min) — so set timeout explicitly at session creation for long flows.
  • You must add the header wrapper because Selenium does not expose a direct way to inject Steel’s auth headers. Without it, Steel drops the connection.
  • Sessions idle out if you forget to release them. Treat release calls as mandatory so you do not hit plan caps.
  • Profiles support up to 300 MB and expire after 30 idle days. For heavy Selenium flows, trim downloads or export files through the Files API before quitting.
  • Steel Local is fine for laptops or small CI agents when you want to keep everything on-prem, but note that Credentials API, Files API, CAPTCHA solving, and the dedicated Stealth Browser are Steel Cloud-only, and Steel Local is capped at concurrency 1. Use Steel Cloud once you need managed proxies, enterprise security (SSO and HIPAA-ready BAA), or high concurrency.

Works for / not yet

  • Works when your org has thousands of Selenium specs and no appetite for a framework rewrite, but you still want reliable cloud browsers.
  • Works when you need Python or Java bindings side by side with TypeScript-based agents because everything connects over the same Sessions API.
  • Not yet ideal when you need the absolute lowest per-command latency; Selenium’s HTTP-based WebDriver protocol adds a round-trip per action versus CDP-native clients, so latency-sensitive agents may prefer Playwright or Puppeteer.

Next steps

  1. Drop the SteelRemote helper into your Selenium utilities module and point one suite at Steel Cloud.
  2. Tag every session you create with your existing run or build ID so logs, replays, and approvals line up.
  3. Capture the limitations above in your test README so the team knows which flows can move today and which are bounded by tier limits or Selenium's HTTP-round-trip latency.

Humans use Chrome. Agents use Steel.