AutoGen's multimodal web surfer drives a real browser, which is exactly the component that gets blocked. It has no proxy option. It does have one parameter that makes the problem solvable, and it is easy to miss. We read release python-v0.7.5 on 20 September 2026.
Dates first, because they matter here. That release is from 30 September 2025 and the last push to the repository was 15 April 2026. The readme we read carries no notice about the pause.
Two options and no proxy
The agent builds its launch arguments like this:
launch_args: Dict[str, Any] = {"headless": self.headless}
if self.browser_channel is not None:
launch_args["channel"] = self.browser_channel
That is the whole configuration. Headless mode, and a browser channel if you named one. Nothing in the constructor adds an address, and nothing lets you extend that dictionary.
Bring your own context
The constructor ends with two optional parameters that most people skim past:
playwright: Playwright | None = None,
context: BrowserContext | None = None,
And the setup code only creates its own when neither was given: if self._context is None:.
So the supported route is to build the browser yourself, with the library's own proxy settings, and hand the context in. Those settings take the address and the login in separate fields, which is the rule we covered on our Playwright MCP page. A login written inside the server string is dropped there.
This is a good shape, and we said the same about the crawling reader on our LlamaIndex page. A component that accepts the object does not need a parameter for every option the object has.
What you inherit
Passing your own context means you also stop inheriting what the agent would have set. There is exactly one thing in that category, and it is worth knowing:
self._context = await browser.new_context(
user_agent="Mozilla/5.0 ... Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0"
)
A fixed user agent, naming a browser version from early 2024. Two things follow. On the default path every run announces that same ageing version, which is a signal in its own right. And on your path it is not applied at all, so set a user agent on the context you build.
| What the context needs | Who sets it |
|---|---|
| the proxy server | you |
| the proxy login | you, in separate fields |
| the user agent | the agent on its own path, you on yours |
| the viewport | the agent, after the context exists |
The persistent profile
There is a third path. Give the agent a data directory and it launches a persistent context instead:
self._context = await self._playwright.chromium.launch_persistent_context(
self.browser_data_dir, **launch_args
)
Same two launch arguments, so still no proxy. And because this branch never calls the context builder, the fixed user agent is not applied here either. Switching to a stored profile therefore changes more than where cookies live.
Which proxy type fits it?
Residential, for the sites that answer a hosting address differently. Our own paired test is the size of that effect: 4 of 13 sites answered a residential address differently from a server one, with plain requests rather than a browser, so treat it as the address effect alone.
Size it for a browser. This agent loads full pages and takes screenshots of them, so images, fonts and scripts are all on the line, and a per gigabyte plan should be sized for pages rather than for steps.
One practical note for the context you construct. An allowed address means it needs no credentials at all, which keeps a password out of the code that builds the browser: on a Residential Premium plan your machine's address can be allowed, up to 150 per plan. The residential proxies page lists the plans, and the plan API manages allowed addresses from code.
What breaks
- You cannot find the proxy parameter. There is not one. Pass a context instead.
- Your login is ignored. It was inside the server string. The browser layer wants separate fields.
- Your own context looks like a different browser. The fixed user agent is only set on the agent's own path.
- A persistent profile behaves differently. That branch skips the user agent as well.
- Something else in the framework still goes direct. We read the web surfer only.
What this page does not cover
We read the release as text and did not run the agent, so we did not watch it use an address, did not pass it a context and did not measure a run's traffic. We read the web surfer closely and did not read the rest of a very large framework, so other components may fetch with their own rules. The usual risk is reversed here: with a release a year old and a push five months old, this page is unlikely to go stale quickly. We will look again by 20 December 2026.
Where to go from here
Proxies for Playwright MCP covers the browser library underneath, including where a login has to go and why SOCKS with one does not work. Proxies for LlamaIndex covers the same pass your own object pattern in a retrieval framework. Proxies for GPT Researcher covers a framework where two browser scrapers cannot take an address at all.
Sources
- The launch arguments, the optional playwright and context parameters, the condition that only builds a context when none was given, the fixed user agent on that path, and the persistent profile branch (python/packages/autogen-ext/src/autogen_ext/agents/web_surfer/_multimodal_web_surfer.py). microsoft/autogen, release python-v0.7.5 of 30 September 2025, read 20 September 2026.
- Stars, forks, the release list and the last push date. GitHub API, read 20 September 2026.
- Our paired address test of 19 September 2026: 16 URLs, plain requests, two runs from our server and two through a residential line of our house plan. Raw output is kept in the research folder of our OpenClaw page.
- Plans, allowed addresses and per gigabyte pricing. HProxy documentation, hproxy.com/docs, 20 September 2026.


