Botasaurus puts a proxy on both of its decorators, the browser one and the plain request one, with the same argument in both. That part is pleasant. What is not documented is how it treats a list, how that differs from a list your own function returns, and what an address with a login quietly starts on your machine. We read all three of its packages on 20 September 2026.
One version note first: this project publishes no releases and no tags at all, so the head of the main branch is the only version there is. We read it at commit 6c9260de, dated 26 July 2026.
The three shapes
from botasaurus.browser import browser
@browser(proxy="http://GATEWAY_HOST:GATEWAY_PORT")
def scrape(driver, data):
...
| What you pass | What each task gets |
|---|---|
| A string | that address, every time |
| A list | the next address, cycled in order |
| A function returning a string | whatever it returns for that item |
| A function returning a list | one entry, chosen at random |
The last two rows are the trap. The same list behaves differently depending on where you put it: handed to the decorator it becomes an endless cycle and rotates predictably, while a list that comes back from your function reaches a small helper that picks one at random.
Neither is wrong. They are simply different, and only one of them is what most people mean by rotation. If you want predictable round robin, pass the list directly.
Both decorators use the same three lines for this, so moving a task between a browser and a plain request does not change the behaviour.
What a login starts
When the address carries a user name and password, the driver starts a local proxy and passes the browser that local address instead. Your login never reaches the browser, which is the standard answer to the fact that a browser cannot take one.
Here is the part worth knowing. That local proxy is not Python. The helper loads a Node package through a Python to JavaScript bridge and asks it to anonymise your address:
chain = require("proxy-chain") # loaded through a JS bridge, from Python
So a Python scraper with a credentialed proxy is also running a Node process. When the address has no login, the helper checks that first and hands the address straight to the browser. No bridge, no Node, no extra process.
That explains two reports on its tracker that otherwise look unrelated: a timeout when the library runs inside a background worker, and a proxy that stops working once the program is compiled into a single binary. Both are the same dependency, met in two places where a Node runtime is awkward.
Rotation and browser reuse
The address is chosen when a browser is created. The library can also reuse browsers between tasks, which is good for speed and directly at odds with rotating per task: a reused browser keeps the address it was started with. Its tracker has an issue on exactly this.
So pick one. Rotate per task and let each task start its own browser, or reuse browsers and accept that the address is per browser.
Which proxy type fits it?
Residential, for the sites that refuse a hosting address. In our paired test a residential address changed 4 of 13 answers, while four sites refused both. The stealth features exist for those four; the address is for the rest.
Then, specifically for this library, consider an allowed address. On an HProxy Residential Premium plan your machine's address can be allowed, up to 150 per plan, so the address carries no login. With most tools that is a tidiness argument. Here it removes a moving part: no local proxy, no bridge, no Node process, and none of the two failures above. That is a real reason to prefer it, and it comes from their code rather than from our sales page.
If you do want a list of ports to rotate through, pass them as a list to the decorator and let each task take the next one. A retry is still worth writing, since a sticky address can change early when its device leaves the network. The residential proxies page lists the plans and the plan API manages allowed addresses from code.
What breaks
- An authenticated proxy does nothing. Several reports across 2024. Check that the Node side is available at all.
- It works in a script and fails in a worker. The bridge again.
- It works locally and fails compiled. The bridge again. An allowed address avoids it.
- Rotation has no effect. You are reusing browsers, so the address is fixed per browser.
- Rotation is not in the order you expect. Your function returned a list, which is picked at random.
- 407 Proxy Authentication Required. The login is wrong. Our 407 guide covers it.
What this page does not cover
We read three repositories as text and ran none of them, so we did not watch the local proxy start, did not time the bridge, and did not reproduce the worker or compiled binary failures. The rotation behaviours are read in the source and are documented nowhere, which is precisely the kind of thing that can change quietly. Because the project publishes no releases, two installations made on different days can differ. We will read the proxy branches again by 20 October 2026.
Where to go from here
Proxies for Crawlee covers a scraper that starts the same local proxy, from Node where it belongs. Proxies for Steel Browser does it a third time, and also counts the bytes that used your line. Proxies for Patchright covers the other Python stealth browser, where the proxy option is inherited untouched.
Sources
- The proxy argument and the list cycle in both decorators (botasaurus/browser_decorator.py, botasaurus/request_decorator.py), the random pick for a list returned from a function (botasaurus/decorators_common.py), and the documented example (docs/docs/what-is-botasaurus.md). omkarcloud/botasaurus at commit 6c9260de, 26 July 2026, read 20 September 2026.
- The local proxy and the browser argument (botasaurus_driver/core/config.py). omkarcloud/botasaurus-driver at commit db1d2916, 30 July 2026.
- The authentication helper, its check for a login and the JavaScript bridge. omkarcloud/botasaurus-proxy-authentication, read 20 September 2026.
- Issues 109, 113, 114, 171, 193 and 264 on authentication, SOCKS, the worker timeout, rotation with browser reuse, and compiled binaries. Botasaurus issue tracker, read 20 September 2026.
- Our paired address test of 19 September 2026. Raw output is kept in the research folder of our OpenClaw page.
- Plans, allowed addresses and sticky sessions. HProxy documentation, hproxy.com/docs, 20 September 2026.


