browser-use drives a real Chromium browser through Playwright so an AI agent can read pages, click and fill forms on its own, which means the proxy goes on the browser launch, not on the model call. You configure it once with a ProxySettings object passed to the Browser, and every page the agent opens then exits through that IP. The model endpoint the agent reasons with is authenticated by your API key, so routing it through a proxy changes nothing about its rate limit. The browser is the half that touches real websites and inherits their defenses, and that is the half a proxy is for.
We run the proxy network this kind of traffic rides on, so we see the shape of it from the supply side: agents driving headless Chromium, hammering the same defended sites a scraper would, from a handful of server IPs until those addresses burn. This is the practical guide to giving a browser-use agent a proxy that keeps it from being blocked on the third action: where the setting lives, why these agents need residential rotation specifically, and how to isolate one agent from the next. Before a real run, point the proxy checker at an exit to confirm it is alive and leaving from the country you expect.
How do you give browser-use a proxy?
Pass a ProxySettings object to the Browser object, which is the same thing as BrowserSession. The server, username and password fields are the Playwright proxy shape, and the agent runs against the browser you configured:
from browser_use import Agent, Browser, ProxySettings
from browser_use import ChatOpenAI # any model wrapper browser-use ships works here
llm = ChatOpenAI(model="gpt-4.1-mini")
browser = Browser(
proxy=ProxySettings(
server="http://203.0.113.7:8080",
username="user",
password="pass",
bypass="localhost,127.0.0.1",
),
)
agent = Agent(
task="Open the product page and report the current price",
llm=llm,
browser=browser,
)
# await agent.run() inside an async function
Because the proxy is a Chromium launch setting, one detail carries over from Playwright: Chromium accepts a socks5:// server but will not do username and password authentication on a SOCKS proxy. For an authenticated exit, use an HTTP proxy URL, which is what most rotating gateways hand you anyway.
The proxy goes on the browser, not the model
This is the point most setups get backwards, so it is worth being exact. A browser-use agent produces two streams of traffic. One is the reasoning: the agent sends the page state to a model and gets back the next action. That call carries your API key, and the provider counts it against the key no matter which IP it leaves from, so a proxy cannot lift that limit. The other stream is the browsing: every navigation, asset and form post the agent drives through Chromium, aimed at real websites that meter and challenge per IP.
Only the second stream benefits from a proxy, and it benefits a lot. The same boundary holds for every agent framework, which we lay out in full in proxies for AI agents: the proxy fixes IP-level problems on the sites the agent visits, and the model quota stays with the key.
Agent reasoning
model call, key-bound, no proxy
Chromium browsing
real sites, metered per IP
ProxySettings on Browser
residential exit for the browser
Believable session
one identity per task
Why AI browser agents need residential rotation
An agent that drives a full browser is the hardest kind of automation to hide, for two reasons that stack. It pulls the whole page (scripts, fonts, images) and runs the JavaScript, which hands anti-bot systems a large fingerprint surface to read. And it repeats, session after session, often from one cloud IP. A datacenter address under that load earns a challenge from Cloudflare or DataDome on sight, because a datacenter range announces itself as a server, not a person.
Residential IPs are what change that calculus, because they read as ordinary home connections and clear the reputation checks that bounce datacenter ranges. The rotation rule for agents is sticky by default: hold one residential exit for the full length of a task, so the cookie a site issued to one address keeps arriving from that address, then rotate cleanly to a fresh identity for the next task. An IP that changes mid-task turns one coherent visitor into what looks like a session hijack. The mechanics of holding an exit steady are in rotating vs static residential, and the full list of signals a site reads is in how websites detect proxies.
Per-agent isolation
Running several agents at once is where isolation matters. Give each agent its own Browser with its own proxy and its own user_data_dir, so cookies, local storage and the exit IP never bleed between them. One flagged agent then stays contained instead of tainting the whole fleet:
def make_agent(task, proxy, profile_dir):
browser = Browser(
proxy=ProxySettings(
server=f"http://{proxy}",
username="user",
password="pass",
),
user_data_dir=profile_dir, # separate cookies and storage per agent
)
return Agent(task=task, llm=llm, browser=browser)
agents = [
make_agent("check price in the US store", "203.0.113.7:8080", "./profiles/a"),
make_agent("check price in the DE store", "198.51.100.14:8080", "./profiles/b"),
]
Pin geography per agent while you are at it. An identity that logs in from one country and makes its next request from another has described a bot in a single sentence, so keep one country per task and match it to what the task is about.
Verify the exit before you turn the agent loose
An agent acts on its own, so a dead or mislocated proxy does not simply fail one request, it wastes an entire autonomous task and undoes whatever the agent had already done before the exit went bad. That makes verification worth more here than in a plain scraper, where a failed fetch is just a retry. Check each proxy before a run rather than after: confirm it answers, measure its latency, and read back the country it actually exits from, because a residential label means nothing if the IP resolves somewhere the task did not intend. Our proxy checker reports exit IP, real country, latency and anonymity grade in one paste, which is quicker than scripting those probes into the agent's startup and catches the leaking or mislabeled exits before they cost you a task.
Budget for the bandwidth
The number people underestimate with browser agents is not the IP count, it is the bandwidth. A raw HTTP scraper pulls a few kilobytes of HTML per request. An agent driving Chromium pulls the entire page, often several megabytes per view and many views per task, and on metered residential that adds up quickly. We measured how fast in the headless browser bandwidth study. The practical savings come from pointing the browser at the leanest version of a target that still works, blocking asset loads the task does not need, and reserving the heavy browser runs for the sites that genuinely require them.
Where HProxy fits
We built the network for exactly this mix. Residential proxies with country targeting and sticky sessions handle the defended, geo-specific work a browser-use agent does, ISP proxies give a stable identity for a long task that must not lose its session, and cheap datacenter covers any friendly endpoint the agent calls. Pricing is pay-as-you-go at $0.44/GB with a balance that does not expire, which suits agent workloads that run in bursts rather than a steady stream. Confirm an exit in the proxy checker before a run, and if part of your stack is scripted rather than browser-driven, the Playwright guide covers wiring a proxy into the browser directly. Get the IP, the fingerprint and the rotation right, and a browser-use agent goes back to being a reasoning problem instead of a blocking one.
Sources
- browser-use: browser parameters: the
proxyparameter and theProxySettingsfields (server,username,password,bypass). - Playwright: Network and proxy: browser-level proxy configuration and the SOCKS authentication limitation in Chromium.