Proxies & exits
Store a proxy, check it, and understand the exit rule: how one bought gateway becomes many stable addresses, why an address belongs to one profile, and what the guard does while a browser runs.
Where a request comes from is judged before any JavaScript on the page has run, so nothing the browser does reaches it. This page is the half of a profile's identity that lives outside the browser.
Storing one
A proxy is a row: kind, host, port, optional credentials, a rotation setting and a label.
$ curl -X POST http://127.0.0.1:8787/v1/proxies \
-H "Authorization: Bearer $SCALEBROWSER_BEARER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"kind":"gateway","host":"gw.dataimpulse.com","port":823,
"username":"…","password":"…","rotation":"rotating","label":"DE mobile"}'| Field | Values | Notes |
|---|---|---|
kind | http · socks5 · gateway | gateway is a provider endpoint that hands out exits, rather than one exit. |
rotation | sticky · rotating | What the provider does. This is your claim about them, not a measurement. |
label | free text | Give one. A whole pool shares host, port and kind, so nothing else tells two rows apart. |
Credentials are write-only. No endpoint returns them, and the type that carries them cannot be serialised at all, so a proxy password cannot leave through a response by accident. They are encrypted at rest with the daemon's master key.
A row whose credentials will not decrypt, for instance a database restored without its key, is flagged credentials_unreadable. It stays listable and deletable, and every path that would use it fails closed: an authenticated proxy is never run without its credentials, because that would send the session out over your real address.
Checking one
Two calls, and the difference matters.
| Call | What it does |
|---|---|
POST /v1/proxies/:id/check | Runs the real check through a saved proxy: reachability, exit address and country, and the fingerprint verdict. Stores the result and emits a proxy_checked event. |
POST /v1/proxies/check | The same check on an unsaved configuration. Stores nothing, emits nothing, and adds latency_ms. Test before you persist. |
An unreachable proxy is reported as healthy: false, not as an error. The row exists; it just does not work right now.
Changing the connection identity clears the cached exit. A PATCH touching host, port, kind or credentials drops the stored country and health, because the geo gate must not judge a new endpoint by the previous one's exit. Run a check afterwards. Changing only the rotation setting or the label keeps the cache.
One gateway, many profiles
A residential or mobile pool is bought once and split into many stable exits by a session tag, a value the provider reads out of your username or password. The daemon knows the spelling for fourteen providers and writes the tag for you, so one bought account serves many profiles with a different address each.
| Provider host | Where the tag goes | Shape |
|---|---|---|
brd.superproxy.io | username | up to 20 alphanumerics |
pr.oxylabs.io | username | up to 20 alphanumerics |
residential.proxy.decodo.com | username | up to 20 alphanumerics |
proxy.soax.com | username | up to 32 alphanumerics |
gw.netnut.net | username | 8 digits |
p.webshare.io | username | 6 digits |
rp.scrapegw.com | username | up to 20 alphanumerics |
gw.dataimpulse.com | username | up to 20 alphanumerics |
unmetered.residential.proxyrack.net | username | up to 20 alphanumerics |
pool.infatica.io | username | up to 16 alphanumerics |
geo.iproyal.com | password | exactly 8 alphanumerics |
rp.evomi.com | password | up to 16 alphanumerics |
residential.rayobyte.com | password | up to 16 alphanumerics |
superproxy.zenrows.com | password | up to 16 alphanumerics |
The host is matched on its ending, so a regional hostname such as de.gw.netnut.net resolves too.
An unknown host is not an error. The daemon leaves the credentials exactly as you entered them and simply cannot draw a new session. Guessing a spelling would be worse than not trying: a malformed username is a refused connection at most gateways, which reads like a dead proxy.
One address, one profile
Two of your profiles arriving from the same address at the same site is the cheapest link there is. The daemon therefore treats an exit address as owned.
When a profile starts and the address it draws already belongs to another profile, the daemon draws a new session tag and tries again, up to five times. If every draw is taken, the start is refused with error 4013, which is deliberately not 4002: this is not a proxy problem, and sending you to check your proxy would send you looking for something that is not there.
The comparison unit
Not the raw string. For IPv4 it is the address; for IPv6 it is the /64 prefix, because a subscriber line draws new addresses out of that prefix at will, and comparing whole IPv6 addresses would report "different" for every pair while protecting nothing.
Two different addresses inside one IPv4 /24 count as neighbours. That is advisory by default and can be made blocking.
How long ownership lasts
By the kind of address, because a mobile address is recycled in days and a datacenter address is not:
| Address kind | Ownership lasts |
|---|---|
mobile | 3 days |
residential | 30 days |
datacenter | 90 days |
unknown | 30 days |
unknown deliberately takes the middle term rather than the longest. A deployment without an address dataset classifies everything as unknown, and the longest term there would drain the pool while looking careful.
The guard, while a browser runs
An exit can change under you: a provider rotates, a session times out, a route flaps. Two beats watch for it:
- Keep-alive, every 30 seconds, only where the provider documents an idle cut-off. A couple of hundred bytes that say nothing and hold the session. Oxylabs, Decodo and SOAX drop a session after 60 seconds of silence, Bright Data after five minutes, so a resting profile would otherwise lose its address between two clicks.
- Address check, every 120 seconds. The real question, and the only one that can cut a wire.
The verdict rides on the event stream as exit_guard_changed, in one of four states:
| State | What it means |
|---|---|
ok | The address is the one this profile owns. |
degraded | One or two probes in a row got no answer. Nothing is cut. |
unverified | Three in a row got no answer. Still nothing is cut: the wire is unverified, not proven wrong. |
severed | The address moved onto one another profile owns. The wire is cut, and stays cut. |
A silent probe is not an address change. If it were, one unreachable probe endpoint would sever every healthy profile behind it, and the outage would cause exactly the damage the guard exists to prevent. degraded and unverified are statements about our knowledge, and neither cuts anything.
A severed wire is not reconnected automatically either, because an automatic return would show the page a second address change mid-session.
What the promise actually is
A number, not the word "never". The relay opens its own upstream per browser connection, so between a provider-side change nobody announced and the next check there is a window by construction:
- zero at start, measured live rather than read off a stored field
- 30 seconds around a rotation whose period two matching gaps have confirmed
- at most 120 seconds otherwise
The rotation shape is measured, with two probes, and never read off the row's rotation setting: that field is a customer's claim about a provider, and the provider is the one that decides.
Turning the rule off
GET and PUT /v1/exit-rule read and set it for this machine, and the management app has the switch under Settings. Off means starts are never refused for a taken address and nothing is watched.
That is a real choice for a single-profile setup and a bad one for a fleet.
What the daemon deliberately does not do
It does not rewrite traffic. There is no man in the middle, no header injection, no certificate of ours in the chain. A proxy is a proxy, and the coherence work happens inside the engine where a page can be told the truth instead of a rewritten version of it.
A datacenter exit therefore stays a datacenter exit. No patch in the browser reaches that, which is why sharp targets presuppose a terminating residential or mobile proxy. See Coherence & proxies.
Next
- Coherence & proxies: what the exit is compared against before a launch.
- Profiles & personas: the half of the identity that lives inside the browser.
- Events: the
exit_guard_changedandproxy_checkedframes. - Errors:
4002and4013, and why they are different.