zendriver is a free, open source data extraction & web scraping project written in Python and released under AGPL-3.0. It has 1,450 GitHub stars, 108 forks and 57 open issues, and was last pushed 2 days ago. On this registry it ranks #91 of 128 tracked projects in Data Extraction & Web Scraping, with 5 head-to-head comparisons available.

What is zendriver?

Zendriver is a Python framework for undetectable, asynchronous web scraping and browser automation that drives a real Chrome instance over the Chrome DevTools Protocol instead of Selenium or WebDriver.

What it is

Zendriver is an async-first web automation and scraping library published on PyPI as zendriver and documented at zendriver.dev. It is a fork of ultrafunkamsterdam/nodriver, created to add new features, compile unmerged bugfixes, and increase community engagement, and it keeps its predecessor's batteries-included approach. Everything runs through the Chrome DevTools Protocol with an async Python API, so a script can visit pages, scrape content, and execute JavaScript using a real browser in just a few lines of code.

The concrete problem it addresses is bot detection: traditional Selenium and WebDriver automation is comparatively slow and comparatively easy for anti-bot solutions to spot. Because Zendriver speaks the Chrome DevTools Protocol directly rather than going through WebDriver, the README describes it as almost impossible to detect, which matters for targets protected by services such as Cloudflare. It also solves a packaging problem — browser automation has been difficult to containerise, especially with a real GPU-accelerated, non-headless Chrome — through an officially supported Docker project template.

Key capabilities

  • Drives a real Chrome browser over the Chrome DevTools Protocol with no Selenium or WebDriver in the stack, covering page visits, content scraping, and JavaScript execution.
  • Ships first-class Docker support via the cdpdriver/zendriver-docker project template, which runs a real, GPU-accelerated (not headless) browser in a container on Linux.
  • Handles cookie and profile management automatically: a fresh profile is used by default and cleaned up on exit, or cookies can be saved to and loaded from a file to skip repeated logins.
  • Provides smart element lookup by selector or text, including inside iframes, retrying until timeout elapses so a lookup can double as a wait condition.
  • Supports single-element lookup by text through tab.find() with a best_match flag, which ranks candidates by closest matching text length instead of returning the first match.
  • Offers easy debugging through descriptive repr output for elements that renders the element as HTML.
  • Provides page-level utilities such as page.save_screenshot("browserscan.png") alongside zd.start() and browser.stop() lifecycle calls.

Who uses it and how

  • Python developers who need to scrape sites behind anti-bot protection such as Cloudflare without running a WebDriver stack.
  • Teams that want browser automation packaged as a container, using the zendriver-docker template on Linux to run GPU-accelerated Chrome rather than headless Chrome.
  • Operators running repeated automated sessions against sites requiring login, persisting cookies to a file so each run does not repeat the login steps.
  • Contributors and users migrating from nodriver who want open pull requests addressed, including previously unmerged bugfixes for critical bugs.
  • Anyone testing bot detection directly, as in the README example that visits https://www.browserscan.net/bot-detection and saves the results as a screenshot.

Getting started

Install the package from PyPI with pip install zendriver (or the equivalent uv, poetry, or other package-manager command), then run scripts through asyncio.run() with zd.start(); for containerised deployments, use the cdpdriver/zendriver-docker template.

How it compares

Zendriver sits alongside its predecessor nodriver, from which it forks to add features and unmerged bugfixes, and alongside Selenium and WebDriver-based tools, which it replaces at the protocol layer by speaking the Chrome DevTools Protocol directly. Among the tools named in its own documentation, it positions itself as the faster and harder-to-detect alternative to those Selenium/WebDriver solutions while preserving a batteries-included Python API.

When to use it — and when not

Users must operate a real Chrome installation, and the officially supported GPU-accelerated Docker path is Linux-only, so a self-hoster is managing a browser runtime rather than a turnkey service. The project is licensed AGPL-3.0, which may rule it out for teams unwilling to meet copyleft obligations, and the repository currently carries 57 open issues; the README also notes that its parent project restricted contributions for months, so anyone depending on it should evaluate issue responsiveness before committing.

project readme (upstream, from github) — read inline

Zendriver ✌️

License Pypi Version Issues Pull Requests codecov

This package is a fork of ultrafunkamsterdam/nodriver, created to add new features, compile unmerged bugfixes, and increase community engagement.

Zendriver is a blazing fast, async-first, undetectable webscraping/web automation framework implemented using the Chrome Devtools Protocol. Visit websites, scrape content, and run JavaScript using a real browser (no Selenium/Webdriver) all with just a few lines of Python.

Docker support is here! Check out cdpdriver/zendriver-docker for an example of how to run Zendriver with a real, GPU-accelerated browser (not headless) in a Docker container. (Linux-only)

Features

  • Undetectable - Zendriver uses the Chrome Devtools Protocol instead of Selenium/WebDriver, making it (almost) impossible to detect
  • Blazing fast - Chrome Devtools Protocol is fast, much faster than previous Selenium/WebDriver solutions. CDP combined with an async Python API makes Zendriver highly performant.
  • Feature complete and easy to use - Packed with allowing you to get up and running in just a few lines of code.
  • First-class Docker support - Traditionally, browser automation has been incredibly difficult to package with Docker, especially if you want to run real, GPU-accelerated Chrome (not headless). Now, deploying with Docker is easier than ever using the officially supported zendriver-docker project template.
  • Automatic cookie and profile management - By default, uses fresh profile on each run, cleaning up on exit. Or, save and load cookies to a file to avoid repeating tedious login steps.
  • Smart element lookup - Find elements selector or text, including iframe content. This could also be used as wait condition for a element to appear, since it will retry for the duration of timeout until found. Single element lookup by text using tab.find() accepts a best_match flag, which will not naively return the first match, but will match candidates by closest matching text length.
  • Easy debugging - Descriptive repr for elements, which represents the element as HTML, makes debugging much easier.

Installation

To install, simply use pip (or your favorite package manager):

pip install zendriver
# or uv add zendriver, poetry add zendriver, etc.

Usage

Example for visiting https://www.browserscan.net/bot-detection and saving a screenshot of the results:

import asyncio

import zendriver as zd


async def main():
    browser = await zd.start()
    page = await browser.get("https://www.browserscan.net/bot-detection")
    await page.save_screenshot("browserscan.png")
    await browser.stop()


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

Check out the Quickstart for more information and examples.

Rationale for the fork

Zendriver remains committed to nodriver's goals of staying undetected for all modern anti-bot solutions and also keeps with the batteries-included approach of its predecessor. Unfortunately, contributions to the original nodriver repo are heavily restricted, making it difficult to submit issues or pull requests. At the time of writing, there are several pull requests open to fix critical bugs which have beeen left unaddressed for many months.

Zendriver aims to change this by:

  1. Including open pull requests in the original nodriver repo as part of the initial release
  2. Modernizing the development process to include static analysis tools such as ruff and mypy, reducing the number of easy-to-catch bugs which make it through in the future
  3. Opening up the issue tracker and pull requests for community contributions, allowing the project to continue to grow along with its community.

With these changes in place, we hope to further development of state-of-the-art open-source web automation tools even further, helping to once again make the web truly open for all.

Contributing

Contributions of all types are always welcome! Please see CONTRIBUTING.md for details on how to contribute.

Getting additional help

If you have a question, bug report, or want to make a general inquiry about the project, please create a new GitHub issue. If you are having a problem with Zendriver, please make sure to include your operating system, Chrome version, code example demonstrating the issue, and any other information that may be relevant.

Questions directed to any personal accounts outside of GitHub will be ignored.

Frequently asked questions

Is zendriver free to use?

zendriver is open source under the AGPL-3.0 licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does zendriver do?

A blazing fast, async-first, undetectable webscraping/web automation framework based on ultrafunkamsterdam/nodriver. Now with Docker support!

What is zendriver written in?

zendriver is primarily written in Python. Its source is publicly available at https://github.com/cdpdriver/zendriver, and it has 1,450 GitHub stars.