Use case

Proxies for Steel Browser: write the scheme, and read the bytes

Set a proxy on a self-hosted Steel Browser session: the proxyUrl shape, the local forwarder holding your login, the bypass list and the byte counters.

HProxy Team··Updated September 20, 2026·6 min read
HProxy.Use case

Free proxies won't hold up here.

Shared datacenter IPs get flagged and dropped fast. When it has to hold, gaming, streaming, accounts, you need mobile and residential IPs that read as a real device, from $0.44/GB, pay as you go.

Proxies for AI Agents

Steel Browser is a self-hosted browser API: you start a session over HTTP, an agent drives it, and you can hand that session your own proxy. The wiring is good, and one detail in the documentation will cost you an afternoon if nobody warns you. We read release 0.5.4-beta and the proxy library it builds on, on 20 September 2026.

Where the proxy goes

curl -X POST http://localhost:3000/v1/sessions \
  -H "Content-Type: application/json" \
  -d '{"proxyUrl": "http://USER:PASS@GATEWAY_HOST:GATEWAY_PORT"}'

That is the whole setting. It is an optional string on the request that creates a session, there is no global configuration for it, and nothing validates it on the way through.

Write the scheme

The project's README documents the address three times, in JavaScript, Python and curl, as user:pass@host:port. Do not copy it. Steel passes your string to its proxy library untouched, and that library decides what is acceptable by reading the protocol with the standard URL parser.

We ran that parser on the shapes people write:

What you writeWhat the parser sees as the protocolAccepted
user:pass@host:8080user:no
host:8080host:no
http://user:pass@host:8080http:yes
socks5://user:pass@host:1080socks5:yes

The first line is the trap. It does not fail as a malformed address. It succeeds as a URL whose protocol is your username, and the library then refuses it because the protocol is not one of http, https or SOCKS. The error names your username as a protocol, which is a confusing thing to read at two in the morning.

Worse, the check happens when a request is made, not when the session starts. So the session comes up looking healthy and the first page load fails.

Your login stays in the server

When you pass an address, Steel starts a small forwarder on a random local port and launches the browser pointing at http://127.0.0.1:<port>, with your line as its upstream. The browser never receives your credentials.

This is worth knowing for two reasons. It is why a browser that cannot accept a proxy login works here at all. And it means the password lives in the server process, so the usual advice applies: keep the logs and the process list to yourself, or use a line that recognises your machine by address instead.

There is also a bypass. PROXY_INTERNAL_BYPASS takes a comma separated list of hosts that skip the proxy, on top of the two the server always exempts. Self-hosted stacks need this: internal calls should not travel out and back through a paid line.

What the session counts

This is the feature that makes Steel unusual, and it deserves more attention than it gets. The forwarder adds up the bytes sent and received for every connection that used your line, deliberately leaving out the bypassed hosts, and the session reports both numbers when it ends as proxyTxBytes and proxyRxBytes.

For anyone on a per gigabyte line, that is your bill, measured per session, by the thing that spent it.

With one condition. In the newest release the counters are read a few lines before the forwarder is closed, and they only grow when a connection closes. Anything still open at that moment contributes nothing, which is exactly what a bug report from 31 July describes: a session that clearly routed its traffic, reporting zero. A fix was merged on 15 September 2026. The newest release is from 25 August, so if you want to trust these numbers, run a build that includes that merge.

Keeping a session cheap

{
  "proxyUrl": "http://USER:PASS@GATEWAY_HOST:GATEWAY_PORT",
  "optimizeBandwidth": true
}

Passing true blocks images, media and stylesheets. The object form takes the same three switches plus a list of hosts and a list of URL patterns, so you can drop a specific analytics domain and keep the rest.

Pair it with the counters above and you have something better than advice: run your job once with the blocking off and once with it on, and compare the session's own numbers. That is a measurement of your workload rather than a rule of thumb.

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. A browser API changes how a page is rendered, not where the request comes from.

Both ports we hand out are accepted here, the plain HTTP one and the SOCKS5 one, because the library allows both. Because the session holds one address for its life, a sticky port fits naturally: one session, one address, and a fresh session when you want a fresh address. Write a retry anyway, 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 if you would rather not put a password in the session body at all.

What breaks

  • The session starts, then every page fails. The address has no scheme. Add http://.
  • The traffic totals are zero. The counters in that release are read too early. Check your build against the September fix.
  • Internal calls go out through the proxy. Add those hosts to the bypass list.
  • 407 Proxy Authentication Required. The login in the address is wrong. Our 407 guide covers it.
  • The bill is larger than the page count suggests. A browser loads everything. Turn the blocking on.

What this page does not cover

We read the project and its proxy library as text and did not run a session, so we have not seen the protocol error in a log, have not measured the byte counters, and have not tested the blocking options. The rejection above follows from the library's protocol check plus our own run of the URL parser, which is the same parser the library uses. Every release of this project still carries a beta suffix, and the counter fix landed three weeks after the newest one, so check your version. We will read these settings again by 20 October 2026.

Where to go from here

Proxies for Crawlee covers a scraper that uses the same forwarder library for the same reason. Proxies for Camofox is the other self-hosted browser server in this family, with a very different answer to the location question. Sticky versus rotating sessions covers the port choice behind one session, one address.

Sources

  • The session option and its schema (api/src/modules/sessions/sessions.schema.ts), the forwarder and the bypass list (api/src/utils/proxy.ts), the session wiring, the byte counters and the close order (api/src/services/session.service.ts), the bandwidth options, and the documented examples (README.md). steel-dev/steel-browser, release v0.5.4-beta of 25 August 2026, read 20 September 2026.
  • Issue 331 on the zero byte counters, pull request 361 which settles them, pull request 339, and pull request 162 which added the bypass setting. Steel issue tracker, read 20 September 2026.
  • The upstream address check and its protocol list. apify/proxy-chain, src/server.ts, read 20 September 2026.
  • Our own parse of 20 September 2026: the four address shapes through the standard URL parser on Node 22. Raw output is kept in the research folder of this page.
  • 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.

Frequently asked questions

How do I give a Steel session a proxy?
Pass proxyUrl in the body that creates the session, with a scheme: http://user:pass@host:port. Steel starts a local forwarder for it and hands the browser that loopback address.
Why is the address in the README rejected?
Because it has no scheme. The parser reads the text before the first colon as the protocol, so user:pass@host:port becomes a URL whose protocol is your username, and the proxy library only allows http, https and SOCKS.
Does the browser see my proxy password?
No. Your line is the upstream of a local forwarder, and the browser is launched pointing at 127.0.0.1. That is also why a browser that cannot take a proxy login works here.
Can I keep internal hosts off the proxy?
Yes. PROXY_INTERNAL_BYPASS takes a comma separated list of hosts, on top of the two the server always exempts. Their traffic takes a passthrough path and is left out of the traffic totals.
Can I trust proxyTxBytes and proxyRxBytes?
Only on a recent enough build. In the newest release the counters are read before the forwarder is closed, so open connections contribute nothing and the totals can come back as zero. A fix was merged on 15 September 2026, three weeks after that release.

Proxies that don't die mid-job

Residential, ISP, datacenter and mobile, verified by the same engine that runs tens of millions of checks. They read as a real device and hold up under load. Pay as you go, and your balance never expires. $0.44/GB is the 2,000 GB+ rate; a single gigabyte is $0.50/GB, with no minimum order.

129M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup

HProxy.

Honest guides and comparisons on proxies, scraping and staying unblocked, from the team that runs the network.

RSS feed