Selenium-Driverless: setup, proxies, licence and hCaptcha.

selenium-driverless is a Python library that drives Chrome with a Selenium-style API and no ChromeDriver. How to install it so it still runs in 2026, an async quick start, how it differs from Selenium, proxies, its licence and maintenance status, and what to do when a site shows hCaptcha.

What Selenium-Driverless is

Selenium-Driverless was written by Aurin Aegerter (“Steve”), known on GitHub as kaliiiiiiiiii; the repository now lives at ttlns/Selenium-Driverless. Its PyPI page sums it up as “Undetected selenium without chromedriver usage (Non-commercial use only!)”. Instead of sending WebDriver commands to a ChromeDriver binary, it starts Chrome itself and drives it over the Chrome DevTools Protocol (CDP), the channel Chrome’s developer tools use. Method names follow Selenium (get, find_element, By, execute_script), but the calls are async.

The PyPI package and the GitHub branch (read and run on 2 November 2026)
PyPI releaseGitHub master
Version1.9.4, 22 October 2024Unreleased, last commit 30 October 2026
LicenceCC BY-NC-SA 4.0 with a changed definition of “commercial”MIT, since 22 October 2026
With numpy 2.5 or newerClicks and typing failFixed
With websockets 14 or newerClosing a tab failsClosing a tab fails

The README lists what it does: “Use Selenium without chromedriver”, “Currently passes Cloudflare, Bet365, Turnstile, and others”, multiple tabs and incognito contexts, proxy authentication and network interception. It also says its isolated script contexts let you “execute javascript without getting detected”. Those are the project’s claims; we did not test them against any anti-bot service.

Is Selenium-Driverless still maintained?

No. On 20 October 2026 the author added a note at the top of the README: “Out of maintenance. Unfortunately, I am no more able to maintain this project due to uni.” It goes on: “I belive that https://github.com/Kaliiiiiiiiii-Vinyzu/patchright/ has surpassed in terms of capabilities and stability.” Our Patchright guide covers that project. When we read it on 2 November 2026 the repository was archived, so it takes no new issues or pull requests.

The last release on PyPI is 1.9.4, from 22 October 2024, and PyPI classifies it as “Development Status :: 2 - Pre-Alpha”. The GitHub master branch moved on after that: a fix for numpy 2 and a licence change were merged on 22 October 2026, but neither was released to PyPI.

Selenium-Driverless licence

The two copies carry different licences, so check which one you have. The 1.9.4 package on PyPI includes LICENSE.md, which says the work “is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License with an addition for Section 1(k)”. That addition reads:

Commercial means primarily intended for or directed towards commercial advantage or monetary compensation. A business, project or public agreement with a commercial intent of any kind which profits more than, or equal to 7’000 US-Dollar per month, or any monetary equivalent to that, is not subject to this definition of NonCommercial.

The file goes on: “If you wish to use this project commercially, you can contact the Author for a custom License. This usually includes a fee of around 5-6% based on your current profit.” On its first run, 1.9.4 prints “This project is licenced under "Attribution-NonCommercial-ShareAlike"” to stderr.

On 22 October 2026 the author merged a pull request titled “change license to MIT license”, after offering in the repository to “change the license to some OSS license”. The master branch now has an MIT LICENSE.txt and no longer prints the notice. No release on PyPI carries that change. If your use is commercial, read both texts and the repository history, and decide with your own counsel which terms cover the copy you install. This is not legal advice.

Install Selenium-Driverless

It needs Python 3.8 or newer and Google Chrome installed; the README says “Chromium not tested”. It pulls in Selenium itself, plus cdp-socket, numpy and scipy. A plain pip install selenium-driverless in November 2026 gets numpy 2.5 and websockets 17, and both break it, so pin them:

Shell · pip, PyPI 1.9.4
pip install selenium-driverless "numpy<2.5" "websockets<14"
  • numpy below 2.5. With numpy 2.5.4, every click() and send_keys() in our run failed with “ValueError: Both input arrays must be (arrays of) 3-dimensional vectors, but they are 2 and 2 dimensional instead.” numpy 2.4.6 works.
  • websockets below 14. With websockets 17.4, closing a tab failed with “AttributeError: 'ClientConnection' object has no attribute 'open'” inside cdp-socket. websockets 13.1 works.

To get the numpy fix and the MIT licence, install the master branch instead; it still needs the websockets pin:

Shell · pip, GitHub master
pip install "websockets<14" \
  https://github.com/ttlns/Selenium-Driverless/archive/refs/heads/master.zip

Quick start in Python

Python · async quick start
import asyncio

from selenium_driverless import webdriver
from selenium_driverless.types.by import By


async def main():
    options = webdriver.ChromeOptions()
    options.headless = True
    async with webdriver.Chrome(options=options) as driver:
        await driver.get("https://your-site.example/", wait_load=True)
        print(await driver.title)

        field = await driver.find_element(
            By.CSS_SELECTOR, "input[name=username]", timeout=10
        )
        await field.send_keys("my-username")


asyncio.run(main())

We ran this on 2 November 2026 with 1.9.4 and the pins above, Python 3.13 and Chrome 156, headless. navigator.webdriver read False. options.headless = True adds --headless=new. On the very first run, the library warned “headless is detectable at first run”, and the user agent said HeadlessChrome. It then saves a user agent without “Headless” in its data folder, and later runs used that.

The README also has a synchronous API, from selenium_driverless.sync import webdriver, which it describes as “asyncified, bugs are to expect”.

How it differs from Selenium

  • No ChromeDriver. Nothing to download or keep in step with your Chrome version. It finds the installed Chrome itself, or you set options.binary_location.
  • Async. You await calls, and properties too: await driver.title, await driver.current_url. Use async with webdriver.Chrome(...) to close the browser.
  • Waits built in. find_element takes a timeout and waits for the element, so most WebDriverWait code goes away.
  • Scripts run in an isolated world. execute_script defaults to unique_context=True: it sees the DOM, but not the page’s own JavaScript variables and functions, and the page cannot see what your script sets. Pass unique_context=False to run in the page’s world.
  • Frames. switch_to.frame() is deprecated; the README reads an iframe with await iframe.content_document and searches inside that.
  • get_attribute reads properties. It is an alias for get_property, so get_attribute("data-sitekey") returned None in our run. For an HTML attribute, call get_dom_attribute().
  • Clicks move the pointer. click() moves the mouse to the element along a path before clicking, unless you pass move_to=False.

The isolated world catches out code ported from Selenium. On our local test page, which defines a function onSolved:

Python · page world vs isolated
await driver.execute_script("return typeof onSolved")
# 'undefined'

await driver.execute_script("return typeof onSolved", unique_context=False)
# 'function'

Use a proxy with Selenium-Driverless

For a proxy without a login, give Chrome its own flag. In our run every request went through the proxy, with Google Chrome and with Chrome for Testing:

Python · proxy flag
options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://203.0.113.10:8080")

For a proxy with a username and password, the library has driver.set_single_proxy() and driver.set_auth(). Both work through a small extension it loads into Chrome with --load-extension, and Google announced that branded Chrome builds ignore that flag from Chrome 137 on; Chromium and Chrome for Testing still honour it. In our run with Google Chrome 156, set_single_proxy failed with “Couldn’t find mv3 extension within 10 seconds”. The workaround suggested in the project’s issue #333, this Chrome flag, did not change that:

Flag from issue #333 (no effect)
--disable-features=DisableLoadExtensionCommandLineSwitch

Pointed at Chrome for Testing 156 instead, it worked: the proxy asked for a login and the next request carried it.

Python · proxy with a login
options = webdriver.ChromeOptions()
options.binary_location = "/path/to/chrome-for-testing/chrome"

async with webdriver.Chrome(options=options) as driver:
    await driver.set_single_proxy("http://user:pass@host:port/")
    await driver.get("https://your-site.example/")

The README also shows a different proxy for each incognito context:

Python · proxy per context
await driver.set_auth("user", "pass", "host:port")
context = await driver.new_context(proxy_server="http://host:port")
await context.get("https://your-site.example/")

Its docstring warns that the context proxy “doesn’t work on Windows”. In our headless runs new_context() did not finish with either browser: with Google Chrome it could not find the extension; with Chrome for Testing it timed out with a proxy and, without one, could not find the extension after switching it on for incognito. Issue #325, still open when the repository was archived, reports the same extension error from new_context on Chrome 135. We did not run it with a visible window.

What Selenium-Driverless does when a site shows hCaptcha

The README’s list of what it “passes” names Cloudflare, Bet365 and Turnstile; the Turnstile entry links to the project’s dev notes, which hold a single media link under “bypass turnstile” and no code. hCaptcha is not on the list, and the package has no captcha code at all.

How a browser looks is one of several things that decide whether hCaptcha challenges you; why am I getting hCaptcha covers the others, starting with the reputation of your IP address. Once hCaptcha is on the page, the site accepts the form only with a valid token in the h-captcha-response field, a P1_ string its server checks with hCaptcha. Invisible hCaptcha needs that token too. Selenium-Driverless does not produce one.

Get an hCaptcha token into a Selenium-Driverless session

NoneCap is an hCaptcha solving API. Keep Selenium-Driverless for the rest of the run, and when a page has hCaptcha, send its sitekey and url to NoneCap, get a P1_ token back, put it in the form and submit. The Python SDK (pip install nonecap) has an async client, AsyncNoneCap, that fits the same event loop, and solve() waits for the result:

Python · get an hCaptcha token
import os

from nonecap import AsyncNoneCap
from selenium_driverless import webdriver
from selenium_driverless.types.by import By


async def main():
    async with webdriver.Chrome() as driver:
        await driver.get("https://your-site.example/signup", wait_load=True)
        widget = await driver.find_element(By.CSS_SELECTOR, "[data-sitekey]")

        async with AsyncNoneCap(api_key=os.environ["NONECAP_KEY"]) as nc:
            solve = await nc.solve(
                type="hcaptcha",
                sitekey=await widget.get_dom_attribute("data-sitekey"),
                url=await driver.current_url,
                user_agent=await driver.execute_script("return navigator.userAgent"),
            )

        await fill_and_submit(driver, solve.token)

Then put the token in both response fields, call the widget’s callback if the page set one with data-callback, and submit. Run that script with unique_context=False: the callback is a function in the page’s own world, which the default isolated world cannot see.

Python · fill the token, submit
import asyncio

FILL = """
const token = arguments[0];
for (const name of ["h-captcha-response", "g-recaptcha-response"]) {
    const el = document.querySelector(`textarea[name="${name}"]`);
    if (el) el.value = token;
}
const box = document.querySelector("[data-callback]");
const cb = box && box.getAttribute("data-callback");
if (cb && typeof window[cb] === "function") window[cb](token);
"""


async def fill_and_submit(driver, token):
    await driver.execute_script(FILL, token, unique_context=False)
    button = await driver.find_element(By.CSS_SELECTOR, "button[type=submit]")
    await button.click()


if __name__ == "__main__":
    asyncio.run(main())

We tested both steps against a local test page with an hCaptcha-style form, a fake token and a stand-in for the SDK call: both fields held the token, the page’s callback received it, and the form posted it as h-captcha-response and g-recaptcha-response. With the default isolated world, the fields still filled and the form still posted, but the callback was never called, which breaks pages that act on it.

Sending the browser’s own user_agent is optional; some sites need it for the token to be accepted. If the browser goes through a proxy, you can pass the same one to NoneCap as proxy (http://user:pass@host:port) so the token and the form come from the same IP address. A solve that returns no token is never charged.

Every field, status and error is in the API reference, and the Selenium guide shows the same flow with plain Selenium. NoneCap solves hCaptcha only; it does not help with reCAPTCHA, Turnstile or other CAPTCHAs.

Solve hCaptcha in Python →

Last updated November 2026.

Frequently asked

What is Selenium-Driverless?
A Python library, selenium-driverless on PyPI, that drives Google Chrome with a Selenium-like API but without ChromeDriver. It starts Chrome itself and talks to it over the Chrome DevTools Protocol, and its API is async. It was written by Aurin Aegerter (“Steve”, kaliiiiiiiiii on GitHub, now ttlns).
Is Selenium-Driverless still maintained?
No. Since 20 October 2026 its README opens with “Out of maintenance”, and the GitHub repository is archived (read-only). The last PyPI release, 1.9.4, is from 22 October 2024. The author’s note points to Patchright as the project that has “surpassed in terms of capabilities and stability”.
Can I use Selenium-Driverless commercially?
Read the licence of the copy you use. The 1.9.4 package on PyPI ships a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 licence with the author’s own definition of “commercial”, and prints a non-commercial notice on first run. The GitHub master branch has been MIT-licensed since 22 October 2026, but no PyPI release carries that yet. If your use is commercial, read both texts and decide with your own counsel. This is not legal advice.
Why does click() fail with “Both input arrays must be (arrays of) 3-dimensional vectors”?
That is numpy 2.5 or newer with the 1.9.4 package: its pointer code calls np.cross on 2D vectors, which numpy 2.5 no longer accepts. In our run it broke click() and send_keys(). Install "numpy<2.5", or the GitHub master branch, which has the fix.
How do I use a proxy with Selenium-Driverless?
Without a login, Chrome’s own flag works: options.add_argument("--proxy-server=http://host:port"). For a proxy with a login, driver.set_single_proxy("http://user:pass@host:port/") needs the extension the library loads into Chrome. Google Chrome 137 and newer refuse to load it; in our run it worked with Chrome for Testing.
Does Selenium-Driverless bypass hCaptcha?
It does not solve it. Its README says it “passes” Cloudflare, Bet365 and Turnstile; hCaptcha is not on that list, and the package has no captcha code. When a site shows hCaptcha, the form still needs a valid token in h-captcha-response. NoneCap returns that token.
Why can’t execute_script see the page’s functions?
Selenium-Driverless runs execute_script in an isolated world by default, so the DOM is shared but the page’s own JavaScript globals are not. Pass unique_context=False to run in the page’s world, for example to call an hCaptcha data-callback.
Is it allowed to use Selenium-Driverless and a solver on a site?
That depends on the site and on what you do there. Automate where you are allowed to: your own sites, your tests, and services whose terms permit it. NoneCap’s terms rule out fraud, credential stuffing, spam and unauthorised access. This is not legal advice.

Start solving hCaptcha in minutes.

1,300 free credits on signup. Pay per solve, credits never expire, failed solves never charged.