Rebrowser: What It Is, How It Patches Playwright and Puppeteer, and How To Use It
Rebrowser is an open-source project that patches Playwright and Puppeteer to strip the automation signals that anti-bot systems detect. Its main target is the Runtime.Enable CDP command, which both libraries call by default and which vendors flag as automation. This article explains what the patches change, how to install and run them, and how to pair rebrowser with proxies.
Justinas Tamasevicius
Last updated: Jul 13, 2026
7 min read

TL;DR
- Rebrowser patches Playwright and Puppeteer to suppress the Runtime.Enable CDP leak that anti-bot systems use to spot automation.
- It ships as drop-in packages on npm and PyPI. Node.js drop-ins keep their original import names through package.json aliases, while the Python package uses the rebrowser_playwright import namespace with the same API.
- The patches fix browser-level detection only. You still need residential proxies to pass IP reputation, rate, and geo checks.
- Test every setup against rebrowser-bot-detector after each version bump, since upstream library releases can break the patches.
What is Rebrowser and why does it exist?
Rebrowser is an open-source project that patches the 2 most popular CDP-based browser automation libraries, Playwright and Puppeteer, to cut down on automation detection. It leaves a thin layer over the originals, applying targeted fixes on top of the existing Playwright and Puppeteer codebases while keeping full API compatibility with them.
Playwright and Puppeteer both call the Chrome DevTools Protocol command Runtime.Enable during normal operation. This command lets a library receive events from the Runtime domain, which it needs to track execution contexts and run JavaScript on a page. The issue with this operation is that calling Runtime.Enable leaves a detectable trace, so anti-bot vendors like Cloudflare and DataDome run a few lines of JavaScript that fire automatically when this command has been used – and that exposes the browser as automated.
Rebrowser fixes this issue by disabling the automatic Runtime.Enable call on every frame. Instead, it manually creates execution contexts with unknown IDs when a frame is created, then resolves the context ID on demand when code needs to run. The result passes the detection check while keeping the standard library behavior intact.
Alongside the patches, rebrowser ships a companion tool, rebrowser-bot-detector, that runs modern detection tests against your patched browser so you can confirm the leak is closed before you rely on it. If you're still weighing the 2 libraries the patches support, see Puppeteer vs. Playwright for web scraping, and for background on how automated browsers run without a visible window, see what a headless browser is.
How Rebrowser patches work: What they modify in Playwright and Puppeteer
Disabling Runtime.Enable sounds straightforward, but the command is deeply integrated into how both libraries manage execution contexts and page initialization. The patches live in the rebrowser-patches repository and change how each library issues CDP commands during browser startup and page interaction. The core target is Runtime.Enable and the related commands that expose automation artifacts, such as injected bindings and execution context metadata.
To understand why this matters, look at how detection works. When a library calls Runtime.Enable, the browser starts emitting Runtime.executionContextCreated events. Anti-bot scripts detect the side effects of this and flag the session. Beyond that command, both libraries leave other prints. Playwright injects __pwInitScripts into the global scope of every page, and page.exposeFunction() in both libraries introduces its own leaks.
Rebrowser patches address the Runtime.Enable leak directly by replacing the automatic call with manually managed isolated contexts. The patches are maintained as a separate repository on GitHub and npm, and they are updated as new Playwright and Puppeteer versions ship.
Each Rebrowser release targets a specific upstream Playwright or Puppeteer version. For example, rebrowser-playwright 1.52.0 corresponds to Playwright 1.52.x, though patch-level numbers can differ and the patched version can trail the newest upstream release. Check the rebrowser-patches repository or the package on PyPI or npm for the latest patched version before you pin a dependency.
For a wider view of the countermeasures these patches sit among, see pro tips for navigating anti-bot systems, and for a related fingerprinting angle, see how to bypass CreepJS and spoof browser fingerprinting.
Drop-in replacement vs. manual patching: Two ways to use rebrowser
These patches are open source, but you don't have to apply them by hand. The Rebrowser project publishes pre-patched packages alongside the raw patch files – giving you 2 paths to the same result. The right choice depends on how much control you need over your dependencies.
Drop-in replacement
Pre-patched packages stand in for the originals. Puppeteer users on Node.js get rebrowser-puppeteer and rebrowser-puppeteer-core, Playwright users on Node.js get rebrowser-playwright and rebrowser-playwright-core, and Playwright users on Python get rebrowser-playwright from PyPI.
On Node.js, the cleanest approach is the package.json alias, which points the original package name at the rebrowser version, so all your imports keep working unchanged.
On Python, pip install rebrowser-playwright installs the rebrowser_playwright package. Imports use rebrowser_playwright.sync_api and rebrowser_playwright.async_api rather than the standard playwright paths, though the API itself matches Playwright exactly.
This is the easiest path and the one to pick for new projects or any setup where you are comfortable swapping a dependency.
Manual patching
Alternatively, apply the patches from the rebrowser-patches repository directly to an existing install. This suits teams that need fine-grained control or are locked into a particular dependency setup. It requires following the repository README and watching for updates whenever the upstream library changes.
Which to choose
Use the drop-in packages for simplicity and reliability. Use manual patching when you need a custom setup or want to inspect just what the patch changes. If you need to ground yourself in the Playwright API before applying patches, work through this practical Playwright web scraping tutorial, and if you're still choosing your automation stack, compare the options in Puppeteer vs. Selenium for web scraping.
Setting up rebrowser with Playwright in Python: Step-by-step
It takes 4 terminal commands to go from zero to a working Python scraper with active patches – environment setup, a sync and async scraper, and a verification script that confirms the Runtime.Enable leak is closed.
Environment setup
rebrowser-playwright requires Python 3.9 or later. Create a virtual environment, then run the 4 commands below to install the package and the browser binary.
Those first 2 lines create and activate a virtual environment so your dependencies stay isolated. pip install rebrowser-playwright pulls the patched library from PyPI, and python -m rebrowser_playwright install chromium downloads the Chromium binary the library needs to launch a browser. Skip this last step and the script will fail at launch time with a missing-browser error.
Basic usage (sync API)
Below, imports come from rebrowser_playwright.sync_api. The API matches standard Playwright exactly, so only the import line differs from a stock script.
It launches headless Chromium, navigates to Books to Scrape, and selects every article.product_pod element on the page – each one wraps a book listing. Inside each product pod, it reads the title attribute from the heading link and the text content of the .price_color span, then prints both. with sync_playwright() as p handles startup and teardown, and browser.close() releases the Chromium process when the loop finishes.
Async usage
When a scraper needs to handle multiple pages concurrently, such as paginating through a catalog or hitting several URLs in parallel, the sync API becomes a bottleneck. The async equivalent below does the same extraction but runs inside an asyncio event loop, which lets you add concurrent tasks later without restructuring the script.
Everything here mirrors the sync version, but every Playwright call is awaited. That double-await pattern on the selector lines – await (await book.query_selector(...)).get_attribute(...) – exists because query_selector itself returns a coroutine in async mode, so you await it to get the element handle and then await the attribute call on that handle. asyncio.run(main()) at the bottom starts the event loop and blocks until the scraper finishes.
Verifying the patches work
A working scraper doesn't guarantee the patches are active. The setup steps above could silently fall back to an unpatched Playwright if the package versions drift, so you should verify explicitly. The script below loads the rebrowser-bot-detector page, fires the standard detection triggers, then reloads the page to refresh the readings and prints the JSON results. The order matters because the detector page defines the dummyFn function that the triggers depend on, so navigation has to come first
Output comes from the #detections-json textarea, which holds a JSON object with 1 key per detection test and a pass/fail status for each. Look for runtimeEnableLeak with a status of PASS – that confirms the CDP-level patch is active. Other tests, such as navigatorWebdriver, viewport, and useragent, may show FAIL under default headless settings, and exposeFunctionLeak will fail because the script deliberately triggers it by calling page.expose_function(). Those results are expected and don't indicate a broken patch.
Add a check like this to any new project so you catch a broken patch before it reaches production. For deeper coverage of the Playwright API, see this practical Playwright tutorial, and for the rendering fundamentals behind dynamic pages, see how to scrape websites with dynamic content. For broader Python context, see this in-depth Python web scraping guide, and if you're new to running scripts, see how to run Python code in the terminal.
Flawless IPs for Rebrowser
Rebrowser manages your browser fingerprints flawlessly, but pairing it with Decodo's residential proxies ensures your IP reputation stays impeccable while you scale.
Cross-language support: Rebrowser beyond Python
Not every team runs Python, and the coverage gaps across ecosystems matter if your automation stack crosses language boundaries.
Node.js has the widest support, with all four packages on npm, namely rebrowser-puppeteer, rebrowser-puppeteer-core, rebrowser-playwright, and rebrowser-playwright-core, while Python support covers Playwright only. rebrowser-playwright is on PyPI, while Puppeteer stays Node.js-only and therefore has a Node.js-only patch.
One difference from the Node.js packages is worth noting. The Node.js drop-ins keep their original import names through the package.json alias, but the Python package installs under rebrowser_playwright, so imports use that namespace instead of playwright.
Other languages are still waiting for official coverage. Playwright supports .NET and Java upstream, but Rebrowser currently ships patched builds for Node.js and Python alone. Developers on those stacks would apply the manual patches or run the automation layer on Node.js. The rebrowser-patches package applies to any Node.js-based Playwright or Puppeteer install regardless of the project's primary language, as long as the automation runs on Node.js.
For language-specific scraping context, see web scraping with Cheerio and Node.js, this JavaScript web scraping tutorial, web scraping in C# for .NET developers, and web scraping with Java.
Pairing Rebrowser with proxies for production scraping
A patched browser passes the CDP check, but that's one layer of a multi-layer detection stack. Websites are also fingerprinted by IP reputation, request rate, and geographic consistency – and those signals live outside the browser entirely. Proxies address that gap, and for scraping at any real scale, they're the difference between a proof of concept and a production pipeline.
Residential proxies are the right pairing because they route traffic through real user IPs that carry clean reputation scores. Datacenter IPs get flagged fast – anti-bot systems maintain blocklists of known hosting ranges, so even a perfectly patched browser behind a datacenter proxy often gets blocked on the first request. Residential IPs don't carry that baggage.
Decodo residential proxies give you a pool of 115M+ ethically sourced IPs across 195+ locations with country, city, and ZIP-level targeting. That matters for Rebrowser users specifically because geo-consistency is one of the signals anti-bot systems cross-check – if your browser fingerprint says US but your IP resolves to a German datacenter, the session gets flagged regardless of whether the CDP leak is patched. Decodo lets you lock the exit IP to the same region as the browser's locale, closing that gap.
Below is a rebrowser-playwright browser launched through Decodo residential proxies. The username follows the pattern user-{account_id}-country-{code}, where the account ID is your Decodo residential username, not a Web Scraping API key.
Remember to use your Decodo residential proxy username and password here, not your Web Scraping API key. The API key fails to authenticate against gate.decodo.com:7000 and returns a 407 Proxy Authentication Required error.
The gate.decodo.com:7000 endpoint applies IP rotation on every request, which pairs naturally with Rebrowser – the patched browser handles fingerprint evasion at the CDP layer while Decodo rotates the underlying IP so no single address accumulates enough requests to trigger rate-based detection.
For sessions that need a stable IP (login flows, multi-page checkouts), add a session parameter to the username and switch to a sticky port. Decodo supports session durations up to 30 minutes, long enough for most stateful scraping workflows. That combination – Rebrowser suppressing the CDP leak, Decodo rotating clean residential IPs with precise geo-targeting – covers the 2 biggest detection surfaces most scrapers face.
When even that stack gets blocked on the hardest targets (sites running aggressive TLS fingerprinting, JavaScript challenges, or rotating CAPTCHAs), Decodo Site Unblocker handles the rest. It manages browser fingerprints, retries, and CAPTCHA solving on Decodo's infrastructure, so you send a URL and get back rendered HTML without managing any of the evasion yourself.
For broader anti-blocking strategy, see web scraping without getting blocked, and for a worked example of proxies paired with stealth, see how to scrape Google without getting blocked.
Rebrowser vs. other stealth tools: How it compares
Rebrowser addresses one specific leak at the CDP layer, which raises a fair question about how it relates to the other anti-detection tools developers commonly reach for.
What sets rebrowser apart is the layer it works on. Rebrowser patches the CDP layer directly by neutralizing Runtime.Enable. Most other tools work higher up, spoofing JavaScript properties or modifying the browser binary.
Tool
Detection layer
Approach
Supported libraries
Works alongside Rebrowser?
Rebrowser
CDP commands (Runtime.Enable)
Patches library internals
Playwright, Puppeteer
–
playwright-stealth
JavaScript properties
Injects JS overrides at page level
Playwright
Yes – covers fingerprint vectors Rebrowser doesn't touch
undetected-chromedriver
ChromeDriver detection
Modifies ChromeDriver binary
Selenium
No – different ecosystem (Selenium, not CDP-native)
nodriver
ChromeDriver detection
Bypasses ChromeDriver entirely
Standalone (Chrome DevTools)
No – replaces the automation library rather than patching it
Camoufox
Browser fingerprint
Modified Firefox binary
Playwright (Firefox only)
Partially – different browser engine, heavier setup
Decodo residential proxies
IP reputation, geo, rate limits
Routes traffic through real user IPs
Any library
Yes – handles the network layer Rebrowser can't reach
- playwright-stealth is a community plugin that injects JavaScript overrides to hide common automation properties. It doesn't address the CDP-level leak, so it complements Rebrowser rather than replacing it.
- undetected-chromedriver and nodriver focus on ChromeDriver-based automation in the Selenium ecosystem, a different approach from the CDP-native libraries that Rebrowser targets.
- Camoufox is a modified Firefox binary with anti-fingerprinting built in. It's a heavier solution than Rebrowser's patch-based approach.
In practice, these tools layer rather than compete. Rebrowser handles the CDP leak, proxy rotation handles IP reputation, and a JavaScript stealth plugin can cover any remaining fingerprint vectors. For a wider framework comparison, see Playwright vs. Selenium in 2026.
Best practices and common pitfalls
A working setup today can break tomorrow. Rebrowser's patches track upstream library releases, and any version mismatch can silently disable the fix – so maintenance matters as much as the initial install.
Version management
Match your rebrowser package version to the Playwright or Puppeteer version your project needs. Watch the rebrowser-patches GitHub repository for updates, since an upstream library release can break the patches if you don't update promptly.
Testing your setup
Run rebrowser-bot-detector after every version update to confirm the patches still hold. Automate this check as part of your CI/CD pipeline so a silent regression never reaches production. During async or proxy sessions, stderr may show [rebrowser-patches] messages such as cannot get world. These are expected with the current patch, and scripts still complete, so a warning alone doesn't signal a failed run.
Common mistakes
- Forgetting to run rebrowser_playwright install chromium (or python -m rebrowser_playwright install chromium) after installing the Rebrowser package.
- Mixing Rebrowser and original Playwright or Puppeteer packages in the same environment.
- Assuming Rebrowser alone is enough. IP-level and behavioral detection still need proxies and human-like interaction patterns.
Staying current
Follow the rebrowser-patches GitHub repository for release notifications. Pin your package versions in production and test updates in staging before you deploy. For the detection layers, Rebrowser alone won't solve it; see this ultimate guide to bypassing CAPTCHAs, how to retry failed Python requests for error-handling patterns, and how to bypass CAPTCHA with Puppeteer for Puppeteer-specific guidance.
Full code
Python sync, basic
Python async
Python sync with Decodo residential proxy
Node.js package.json alias (Puppeteer)
Final thoughts
Rebrowser fixes a specific, critical detection vector. Its CDP-level patches close the Runtime.Enable leak that exposes Playwright and Puppeteer to major anti-bot systems. That fix is narrow by design, and it works best as one layer in a broader strategy that combines patches for the browser, proxies for the network, and human-like patterns for the interaction layer. For production setups, pair rebrowser-playwright with Decodo residential proxies, and you cover both the browser and network layers in one move.
Seamless Rebrowser automation
Pair Rebrowser’s advanced headless capabilities with Decodo's Web Scraping API to effortlessly bypass CAPTCHAs and extract data without breaking a sweat.
About the author

Justinas Tamasevicius
Director of Engineering
Justinas Tamaševičius is Director of Engineering with over two decades of expertise in software development. What started as a self-taught passion during his school years has evolved into a distinguished career spanning backend engineering, system architecture, and infrastructure development.
Connect with Justinas via LinkedIn.
All information on Decodo Blog is provided on an as is basis and for informational purposes only. We make no representation and disclaim all liability with respect to your use of any information contained on Decodo Blog or any third-party websites that may belinked therein.


