Docs · How it works
Coherence & proxies
A profile whose timezone contradicts its exit IP is worse than no profile at all. This is what the daemon checks before it lets one start — and what each setting means for you.
A checker looks for contradictions, not for bad values
This one is worth getting right first, because the rest of the page follows from it. A detection system rarely asks “is this browser suspicious?” — that question has no reliable answer, since real people run every combination of hardware and settings you can imagine. It asks a much cheaper question instead: can these two values both be true at the same time?
A browser reporting Berlin time from a Brazilian address is not an unusual browser. It is an impossible one, and finding it takes a single comparison. The same goes for a browser claiming a graphics card that does not draw the way that card draws, or a Windows profile whose language list contains no Windows. Each of those is a pair, and pairs are easy to check at scale.
So the work is not to make each individual value look good. It is to keep the whole set of answers consistent — with each other, with the machine underneath, and with the network the profile speaks over. The daemon does that in three places: it takes the values it cannot safely invent from the real machine, it aligns the ones it can from your proxy’s exit, and it refuses to start a profile whose values disagree.
What the profile takes from your machine
Some parts of an identity are free to choose, because nothing can check them from a web page: timezone, language, installed fonts, browser version. Others are not, because the machine answers back the moment a page asks it to.
| Taken from the host | What would contradict an invented value |
|---|---|
| The graphics card | A page can make the machine draw something and compare the result. A card that is not there cannot render like the one that is. |
| Screen size and available area | A page can go fullscreen and measure what it got. The desktop decides that number, not the profile. |
| Display scale | It is the divisor for every measurement above, so a scale that disagrees with the geometry breaks both at once. |
Those three are read off the host and written into the profile when it is created and again at every start. Two consequences follow. A profile you copy to another machine heals itself on its first launch there, instead of carrying a desktop that machine cannot show. And two profiles on the same machine report the same card and the same screen — deliberately; see what a fleet shares on purpose.
If the identity and the machine still disagree on the graphics vendor — a profile built on an NVIDIA box, started on an AMD one — the launch is refused rather than patched up, and the dashboard says so in as many words: create the profile again on this machine.
Country, timezone and language: geo_mode
This is the one coherence setting you actually choose. It sits on each profile,
next to an optional expected_country, and it decides what happens
when the country your proxy exits in is not the country the identity was built
for.
| Mode | What it does |
|---|---|
follow_exitdefault |
Rewrites the profile’s timezone and language to match the exit country. If the exit country is unknown, or is one with no entry in the locale table, it changes nothing. |
strict_expected |
Refuses to start unless the exit country equals expected_country. An exit country that could not be determined is also a refusal. |
off |
Enforces nothing. The dashboard marks the profile with a warning, because timezone and language then stay wherever they were. |
follow_exit, and why it sometimes does nothing
Under the default the daemon looks the exit country up in a table of fully
specified locales — 17 countries at the moment — and writes the whole locale
across as one unit: the timezone, navigator.language, the
languages list and the Accept-Language header, which
are then guaranteed to agree with one another. It happens when you assign a
checked proxy at creation, and again at every launch against the live exit.
When the exit country is unknown, or is a country the table does not cover, the profile is left exactly as it was. That is the interesting case, and it is a decision rather than a gap: half a spoof is louder than an honest mismatch. A profile carrying the right timezone with the wrong language — or a timezone with no matching date formatting behind it — fails exactly the sort of pairwise comparison this page is about. An identity that is merely in the wrong country is at least internally consistent.
strict_expected, and what it costs
Strict mode never rewrites anything. It compares, and on a mismatch it refuses the
launch with error 4002 (HTTP 409) instead of starting a
profile whose country story does not hold up. An exit whose country could not be
determined is treated the same way — unverified is not the same as fine.
Strict mode asks for more than the country. It also wants
positive evidence that the exit’s own network fingerprint does not contradict
the profile’s operating system. That evidence has to be collected from
outside the connection, and the launch path collects none — so under
strict_expected a profile with a checked proxy assigned is
refused on those grounds too, with the same 4002. Use
follow_exit unless you specifically want a setup in which nothing
starts without that proof.
The proxy is part of the profile
You bring your own proxy; Scalebrowser neither sells nor runs one. What it does is wire yours into the launch so that nothing leaks around it, and nothing about it reaches your agents.
$ curl -X POST http://127.0.0.1:8787/v1/proxies \
-H "Authorization: Bearer $SCALEBROWSER_BEARER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"kind":"socks5","host":"gw.example.net","port":1080,
"username":"user","password":"secret","rotation":"sticky"}'
$ curl -X POST http://127.0.0.1:8787/v1/proxies/<id>/check \
-H "Authorization: Bearer $SCALEBROWSER_BEARER_TOKEN" # exit IP, country, latency
kind is http, socks5 or
gateway; rotation is sticky or
rotating. The check runs a request through the proxy and
records what came out the far end. That recorded exit is what
follow_exit follows and what strict mode compares against, so run it
once before you rely on either.
Credentials stay inside the daemon
The browser is never handed your proxy’s username and password. The daemon runs a small SOCKS5 server on loopback for each running profile and points the browser at that; the relay then dials your real proxy and adds the credentials on that hop. They appear in no browser command line, in no API response, and in nothing an agent can read — the internal type that carries them cannot be serialised at all, which makes leaking them a compile error rather than a rule someone has to remember.
The relay speaks SOCKS5 to the browser for a second reason: it keeps remote DNS. The browser hands over a hostname rather than an address it resolved itself, so no lookup escapes around the proxy and betrays where the machine really is.
Two leak guards, switched on in the same breath
A proxy carries TCP. Two things in a browser do not necessarily travel over TCP, and both would then leave on the machine’s own address:
-
WebRTC, which gathers candidate addresses over UDP. The launch
forces Chromium’s
disable_non_proxied_udphandling. - QUIC / HTTP-3, which is UDP by construction. It is switched off for the profile.
Both are verified in both directions before the browser is allowed to proceed: a proxied launch missing either guard is refused, and so is a guard set on a launch that has no proxy — that combination is a command line no ordinary browser has, which is a tell of its own.
When credentials cannot be decrypted
Proxy credentials are stored encrypted, under the key you set as
SCALEBROWSER_MASTER_KEY. Restore a database without its key — or onto
a machine that has a different one — and those credentials become unreadable.
The row is then flagged, rather than read as “no credentials configured”, and every use of it fails closed. That distinction matters more than it sounds: an authenticated proxy started without its credentials does not fail politely, it connects directly, and the whole session goes out over the host’s real address. The profile is blocked instead. The proxy stays listed and deletable, so you can re-enter the credentials or remove it.
Your exit is scored before a line of JavaScript runs
This is the part no browser change reaches, and it deserves to be said plainly: the network you arrive on is judged before the page is served. A datacentre or hosting network is a strong signal on its own, and it is read from the address and its owner — not from anything the browser says. A fingerprint that passes every check is still arriving from a cloud VM if that is where it arrives from.
Against sharp targets a terminating residential or mobile proxy is therefore a precondition, not a refinement. It is an operating decision and a recurring cost, and it is worth planning for before you tune anything else.
One useful side effect: a terminating proxy replaces the machine’s network stack with the exit device’s. A Windows profile leaving through a Linux exit therefore shows a Linux network fingerprint quite legitimately — which is why the daemon deliberately leaves that layer out of its operating-system agreement check. Counting it would fail every correctly configured profile.
The badge runs the same check the launch runs
Every profile you list carries a protection object: a level, and the
reasons behind it in plain language. It is not a second opinion — the blocking
checks call the very same functions the launch calls, so “green in the dashboard,
refused at the button” is not a state the two can get into.
| Level | Means | Examples |
|---|---|---|
blocked |
The start will be refused. | No engine installed yet · the identity contradicts itself · the language settings are incomplete · this machine renders without a graphics card · the identity claims another vendor’s card · the proxy’s credentials cannot be decrypted |
warn |
It will start, and something measurably weakens it. | No proxy assigned · the last proxy check failed · country matching is off · the graphics hardware could not be measured · a lot of extensions assigned |
ok |
Everything checkable without starting the browser passed. | — |
Two limits, so the badge is not read for more than it is. Checks that need a command line or a live network path — the leak guards above, the exit country — cannot run on a stopped profile, so they stay at the launch. And “no proxy assigned” is a warning rather than a block on purpose: the profile does start, and it is also the most common reason accounts get flagged, which is exactly why it is worth repeating every time you look at the list.
What a fleet shares on purpose
Profiles on one machine are not fully unlinkable, and pretending otherwise would be the wrong trade. They share the graphics card string, the screen geometry and the display scale, because those are the values taken from the host.
The trade is this. Sharing them means anyone who compares those axes across two accounts can tell the accounts ran on the same machine. Not sharing them means inventing values — and an invented value is a claim the machine can contradict on demand, with one rendered image or one fullscreen call. The first is a link between your own accounts. The second is a profile that reads as manipulated, which costs you every account at once. So the honest value wins, and it wins on every machine rather than as a workaround for a particular one.
The difference between profiles comes from the axes nothing can contradict instead: timezone, language, fonts, browser version, hardware counts, and the input timing described on Human input. Each is drawn from the profile’s own seed, so two profiles differ there by construction — and stay themselves across restarts and machines.
If you need profiles that do not share a graphics card, run them on machines that do not share one.
Next
- Human input — the second gate: how a profile behaves once it is in.
- REST API — the profile and proxy endpoints used above.
- Install & run — the master key, the data directory and the ports.