What Botasaurus Is — and Where the Proxy Goes
Botasaurus is a Python framework that pairs a fingerprint-matching browser with a fast HTTP client for reliable access to public data. You write a task function and wrap it in a decorator — @request for plain HTTP, @browser for a real Chrome-based browser — and Botasaurus handles the plumbing around it.
The proxy is one of those decorator arguments. It isn't set at call time; it lives on the decorator:
@request(proxy="http://USER:PASS@PROXY_HOST:PORT")
def scrape(request, data):
...
Credentials go inline in the URL, and every request the task makes leaves through your German mobile IP. Notably, @browser can carry user:pass into a real browser — Chrome can't do that from a proxy string natively, so Botasaurus routes the browser through its own upstream-proxy layer to make authenticated proxies work.
With a dedicated German endpoint you skip the rotation list most guides reach for — you point the task at one endpoint and rotate on demand at the proxy.
Before You Start
You need four values from your GermanProxy.io account:
- Host and port of your endpoint
- Username and password
The examples use PROXY_HOST, PORT, USER and PASS as placeholders — replace them with your own. Install Botasaurus:
pip install botasaurus
proxy= is built into the core package — no extra install.
Step 1 — Proxy on @request (plain HTTP)
Set proxy= on the decorator, fetch a page, and parse it with soupify:
from botasaurus.request import request, Request
from botasaurus.soupify import soupify
@request(proxy="http://USER:PASS@PROXY_HOST:PORT")
def scrape_heading(request: Request, data):
response = request.get("https://www.example.de")
soup = soupify(response) # returns a BeautifulSoup object
heading = soup.find("h1")
return {"heading": heading.get_text() if heading else None}
scrape_heading()
soupify(response) hands you a BeautifulSoup tree, so you query the page with find and friends exactly as you would elsewhere. The request already left through your German mobile IP because the proxy is on the decorator.
Step 2 — Proxy on @browser (real browser)
For JavaScript-heavy pages, use @browser. Same proxy= argument — and this is where the authenticated-proxy handling matters:
from botasaurus.browser import browser, Driver
@browser(proxy="http://USER:PASS@PROXY_HOST:PORT")
def visit_website(driver: Driver, data):
driver.get("https://www.example.de")
return {"title": driver.get_text("h1")}
visit_website()
Botasaurus wires the user:pass from your endpoint into the browser through its upstream-proxy layer, so the whole browser session — HTML, XHR, fetch — travels over your German mobile IP.
Step 3 — Verify the IP Before You Scale
Confirm the proxy is actually in the path first. Fetch an IP-echo endpoint inside the task and print the result — https://api.ipify.org returns the raw IP:
from botasaurus.request import request, Request
@request(proxy="http://USER:PASS@PROXY_HOST:PORT")
def check_ip(request: Request, data):
ip = request.get("https://api.ipify.org").text
print("Outgoing IP:", ip)
return {"ip": ip}
check_ip()
The browser variant reads it from the page:
from botasaurus.browser import browser, Driver
@browser(proxy="http://USER:PASS@PROXY_HOST:PORT")
def check_ip(driver: Driver, data):
driver.get("https://api.ipify.org")
print("Outgoing IP:", driver.get_text("body"))
check_ip()
If the printed IP is the proxy's egress IP and not your server's, routing is confirmed. If it still shows your own address, re-check the proxy string. A 407 means auth didn't reach the proxy — see how to fix 407 proxy authentication required. For a fuller checklist, see test your mobile proxy setup.
Step 4 — Rotation and Per-Run Proxies (optional)
proxy= accepts more than a single string, if you ever need it:
-
A list rotates automatically across runs:
@browser(proxy=[ "http://USER:PASS@PROXY_HOST:PORT", "http://USER:PASS@PROXY_HOST_2:PORT", ]) def visit(driver: Driver, data): ... -
A callable derives the proxy per run from the
dataitem passed in:def get_proxy(data): return data["proxy"] @browser(proxy=get_proxy) def visit(driver: Driver, data): driver.get(data["url"]) visit({"proxy": "http://USER:PASS@PROXY_HOST:PORT", "url": "https://www.example.de"})
With a single dedicated German endpoint you usually need neither — the static string from Steps 1–2 is enough, and you rotate on demand at the proxy.
HTTP Only — No SOCKS5
Botasaurus supports HTTP proxies only. A socks5:// URL raises an error (the underlying proxy layer doesn't implement SOCKS). Use the http:// endpoint:
- This is the proxy protocol, not your target. An HTTP proxy still tunnels HTTPS target traffic fine —
https://URLs work normally. - If you specifically need SOCKS5 elsewhere in your stack, that's a separate tool choice; for Botasaurus, stick to the HTTP endpoint.
Background on the distinction: SOCKS5 vs HTTP proxy.
Sticky Sessions vs. Rotation
With a dedicated German endpoint you control the IP at the proxy, not in your task code:
- Sticky session: keep one
@browsertask running across a multi-step flow and the German mobile IP stays the same. - Rotation on demand: when you want a fresh IP, trigger rotation at the proxy. There's no per-request IP pool to manage.
See sticky sessions and IP rotation explained and dedicated vs shared mobile proxy.
Why a Mobile IP for Botasaurus at All
Botasaurus is built to make a browser's fingerprint coherent so you can reach public data reliably — but a coherent fingerprint on a distrusted IP still draws friction. The egress IP is judged separately from the browser. Datacenter ranges are widely distrusted; a real German mobile IP rides on carrier-grade NAT (CGNAT), the same shared-IP space thousands of ordinary phone users sit behind, which is why it carries higher IP reputation on German platforms. Pairing a fingerprint-matching browser with a real German mobile IP addresses both halves at once.
For the trade-offs against other IP types, see mobile vs residential vs datacenter proxy and what is a mobile proxy.
Scrape Responsibly
A mobile proxy and a fingerprint-matching browser improve reliability for legitimate data collection — they are not tools to circumvent access controls or platform rules. Keep your Botasaurus runs clean and defensible:
- Respect each site's terms and its
robots.txt; collect only public data you're permitted to use. - Throttle with realistic delays between requests so you don't overload servers — a browser task is heavier than a plain HTTP call.
- Collect only what you need, and handle any personal data in line with the GDPR. See is web scraping legal in the EU.
- Be honest about who you are — don't impersonate a service or misuse a target's security mechanisms.
Whether mobile proxies themselves are lawful to use: are mobile proxies legal.
FAQ
How do I set a proxy in Botasaurus?
Pass proxy= as a decorator argument. On @request use @request(proxy="http://USER:PASS@PROXY_HOST:PORT"); on @browser use @browser(proxy="..."). Credentials go inline in the URL and apply to every request that task makes.
Can Botasaurus use an authenticated proxy in a real browser?
Yes. Chrome cannot take user:pass in a proxy string natively, so Botasaurus routes the browser through its own upstream-proxy layer. Pass the full http://USER:PASS@PROXY_HOST:PORT to @browser and it handles the authentication.
How do I rotate or set the proxy per run?
proxy= accepts a list for automatic rotation across runs, or a callable that receives each data item and returns a proxy string — proxy=get_proxy. With one dedicated German endpoint you usually don't need either.
Does Botasaurus support SOCKS5 proxies?
No. Botasaurus supports HTTP proxies only; a SOCKS URL raises an error. Use the http:// endpoint — it still tunnels HTTPS target traffic fine, the proxy protocol itself just has to be HTTP. See the difference between HTTP and SOCKS5.
How do I parse a page fetched with @request?
Pass the response to soupify(response) to get a BeautifulSoup object, then query it with find and friends. The proxy is set on the decorator, so the request already left through your German mobile IP.
How do I verify the outgoing IP?
Fetch an IP-echo endpoint inside the task and print it: request.get("https://api.ipify.org").text, or driver.get_text("body") after driver.get("https://api.ipify.org"). It should show the proxy's egress IP, not your server's.
Related guides
- nodriver Proxy Setup: Route Chrome via German Mobile IPs
- Camoufox Proxy Setup: Route via a German Mobile IP
- undetected-chromedriver Proxy Setup: German Mobile IPs
CTA
Run your Botasaurus tasks on real German mobile IPs. Get your German mobile endpoint — HTTP/SOCKS5/OpenVPN, sticky sessions, on-demand rotation, fair-use 20 GB/day, from a transparent EU provider. Browse the plans to get started.
Get a German mobile proxy: Real 4G/5G IPs from Germany, fair-use 20 GB/day — compare German mobile proxy plans or get a dedicated proxy on the Blue network.