How CloakBrowser Assembles a Coherent Launch
For CloakBrowser, a launch is the point where a proposed browser identity becomes a real process with real network and window behavior. The useful question is therefore not which option to pass first, but how binary selection, GeoIP, proxy routing, WebRTC, locale, timezone, and viewport decisions interact before a page exists. Following that control flow helps a reader interpret both a successful launch and a failure caused by a capability or environment that the wrapper cannot safely assume.
From launch call to browser process
A CloakBrowser launch begins with a binary decision. The wrapper first checks whether the caller supplied a local executable override. If not, it resolves the requested version and platform, determines whether a valid license selects a Pro path, and looks in the local cache before downloading. Official downloads are verified before extraction, but that trust step does not itself configure the browser. It only establishes which executable is allowed to proceed. The chosen binary is an important input to everything that follows because the wrapper gates some behavior by binary version.
If GeoIP is requested, the wrapper resolves location before starting Chromium. It discovers the egress address through an IP-echo service, looks that address up in a cached GeoLite2 database, and obtains a timezone and a locale. With a proxy, the egress address should be the proxy’s exit address; without one, the lookup describes the machine’s public connection. The wrapper reuses the discovered address for WebRTC fingerprinting when possible, so the browser does not present one address to the site’s HTTP connection and leak another through an ICE candidate.
This stage has an intentional failure boundary. A requested GeoIP result is not silently replaced with the container’s UTC clock and default locale if the required values cannot be determined. The current implementation and changelog describe unresolved requested location as a launch error, while explicit timezone and locale values can remain valid without a successful location lookup. That choice favors an explicit failure over a browser that appears to have a coherent location while actually carrying an accidental one.
Proxy resolution comes next. A proxy without credentials can be passed to Playwright in its normal proxy configuration. A SOCKS5 proxy, and a credentialed HTTP proxy on binaries that support Chromium’s native inline authentication, is instead represented as a Chromium --proxy-server argument. The wrapper reconstructs credentials from either a URL or a settings object and URL-encodes special characters so Chromium does not truncate or misread them. Older binaries and some platform/version combinations do not support the native HTTP path, so credentialed HTTP traffic falls back to Playwright’s proxy object.
That version-aware split is easy to miss because the public option looks the same. The caller may pass one proxy string, but the wrapper chooses a different transport boundary depending on the resolved executable. This is a good example of why CloakBrowser’s launch function is more than a convenience alias for Playwright: it translates one stable API into a capability-appropriate process configuration.
The wrapper then assembles Chromium arguments. It starts with default stealth arguments when enabled, adds any GPU blocklist bypass required by headed mode or Windows, applies caller-supplied arguments, and finally adds dedicated timezone and locale flags. Arguments are deduplicated by the portion before =. The effective precedence is defaults first, caller choices second, and dedicated parameters last. If a caller supplies both a default and a replacement fingerprint flag, the later value wins instead of leaving two competing flags in the final command line.
The resulting command is passed to Playwright together with the selected executable and the default arguments that should be suppressed. Playwright starts Chromium and returns a browser or browser-owned context. The caller can then create a page using the ordinary Playwright API. If the caller requested humanization, the wrapper applies that behavioral layer after launch; the binary and launch arguments still provide the browser-level identity, while the wrapper changes how later actions are produced.
Consider a caller who supplies a proxy, enables GeoIP, sets an explicit locale, and asks for automatic WebRTC IP handling. The wrapper does not treat those inputs as four unrelated toggles. It first discovers what the route actually looks like, retains the caller’s explicit locale, fills only the missing location value, and carries the discovered exit address forward to the WebRTC argument path. It then resolves how the proxy should be represented for the selected binary and constructs one final argument set. The value of this ordering is not cosmetic. Each later decision can use a fact established by an earlier one, while an explicit caller choice is not accidentally overwritten by an inferred value.
The same example shows why a launch can fail before Chromium starts. If the caller asks for GeoIP but the database, echo service, or required lookup result is unavailable, the wrapper does not quietly launch with an unrelated timezone and locale. If a proxy URL contains credentials that the selected binary cannot accept inline, the wrapper can choose the Playwright proxy representation instead of sending an incompatible Chromium argument. If a caller pins an older executable, the behavior changes because the wrapper evaluates the pin rather than assuming that the newest binary’s capabilities are present.
The final argument list is consequently an important boundary between intent and execution. A caller may provide a fingerprint flag that conflicts with a default, a raw timezone flag that overlaps with a named parameter, or a window size that conflicts with automatic maximization. Deduplication gives the final value a defined owner: caller values replace defaults, and dedicated timezone/locale parameters are applied after that. Geometry choices are handled separately at context creation, but the wrapper still suppresses automatic maximization when the caller has already chosen a geometry. The precedence is deterministic even when the inputs are not.
This design also limits what one browser process can represent. A startup flag belongs to the Chromium process, while a context is created later inside that process. A process-wide locale or timezone cannot automatically become a different value for every context without another mechanism or another process. CloakBrowser’s choice is to keep the value native and consistent for the process rather than silently emulate it per context. That is a coherent trade-off, but it matters to any application that wants several unrelated identities at once.
The sequence separates decisions that are often blurred together. The binary resolver owns executable selection; the GeoIP and proxy layers own external network facts and transport representation; the argument builder owns precedence; Playwright owns process startup and the browser object. The wrapper coordinates those owners but does not make their dependencies disappear. A binary can be present but unusable on a host missing system libraries. A proxy can connect but produce an exit location that differs from its DNS name. A valid argument list can still be rejected by the target.
Why placement and version change the result
Locale and timezone show why the placement of a setting matters. In context-oriented Playwright code, a timezone option can be applied through browser emulation mechanisms. CloakBrowser instead sends timezone and locale through Chromium flags, including both the language flag and its fingerprint-locale counterpart where needed. The repository’s tests verify that these values reach the launch arguments and do not become context-level locale or timezone_id settings. The reason is twofold: the values are process-level parts of the browser persona, and CDP emulation can expose a detectable path that a native browser startup setting avoids.
There is a consequence to that decision. A process-wide flag is not an independent setting for every context created from the same browser. If one process must serve several unrelated locations, putting the location in its startup arguments can be too coarse. The design improves consistency within a process by making the constraint explicit; it does not promise arbitrary per-context personas without additional process boundaries.
Viewport handling follows the same principle. In headed mode, the wrapper normally uses no_viewport so page dimensions track the actual browser window. Applying a fixed emulated viewport inside a real window can create a physically impossible relationship between outer and inner dimensions. For older headless binaries, the wrapper uses a fixed default viewport because headless Chromium lacks a visible window and needs deterministic dimensions. Newer binaries that report coherent headless dimensions can use the real surface instead. The threshold is defined in the configuration and checked against the resolved version rather than assumed for every installation.
Maximization is gated for the same reason. On a supported binary, the wrapper can add --start-maximized so the window fills the spoofed screen. If the caller has already selected a viewport, window size, window position, or no_viewport, the wrapper suppresses that automatic choice. A caller’s explicit geometry has authority, but the caller also accepts responsibility for whether the geometry agrees with the selected persona. The result is not “more stealth” merely because a window is larger; it is better only when the window, screen, viewport, and platform story remain compatible.
Proxy authentication is another version boundary. The wrapper knows that an inline credential form is not accepted equally by every distributed binary. The configuration records a first supported version per platform, and the resolver compares the actual or pinned binary against that floor. A rollback to an older binary can therefore change the transport path even when application code is unchanged. The fallback through Playwright is not a failure of the public API; it is a compatibility mechanism. Conversely, assuming that a new launch will always use the same path because the option text is unchanged would hide an important behavioral difference.
The release distinction in the repository makes this concrete. The checked-in configuration contains free platform defaults in the Chromium 145/146 range, while the main documentation and recent changelog describe a newer Pro/current Chromium 151 line. These are separate resolution paths, and the project documents both. A test result obtained with the newer keyed binary should not be attributed automatically to the older free binary. Nor should a version pin be described as the current build simply because it is the executable that happens to be cached.
The argument builder also protects a less obvious interface: the relationship between caller intent and default behavior. If stealth arguments are disabled, the caller can supply their own fingerprint flags. If stealth arguments remain enabled, caller flags replace defaults with the same key rather than being appended as a second instruction. Timezone and locale parameters are applied after that replacement. This makes the final argument list predictable, but it also means a caller should inspect the effective configuration when diagnosing a mismatch. The option they remember passing may not be the value that survived precedence, version gating, and normalization.
The launch pipeline can be viewed as a series of contracts. The binary contract says that the executable exists, is for the current platform, and has the capabilities assumed by the wrapper. The network contract says that the selected proxy, egress IP, timezone, locale, and WebRTC address describe one route. The geometry contract says that the viewport and window model fit the selected binary and persona. The API contract says that Playwright receives familiar browser and context objects. Humanization adds a later behavioral contract rather than replacing any of these earlier ones.
Those contracts explain why a simple launch example can work while a more ambitious configuration fails. The basic call may use cached defaults and no external location inference. Adding a proxy introduces authentication and reputation questions. Adding GeoIP introduces a database and echo-service dependency. Choosing headed mode introduces display and window geometry. Pinning an older binary changes capability gates. Enabling humanization introduces timing and selector constraints. Each option adds value only if its new dependency is satisfied.
A careful diagnostic process should therefore start with the resolved executable and effective arguments, not with a detector’s most alarming label. Check whether the intended tier and version actually launched, whether a requested location resolved, whether the proxy route is the one the browser uses, whether WebRTC is aligned, and whether the viewport matches the window model. These checks do not guarantee acceptance by a target, but they distinguish a cross-layer configuration error from a limit of the browser patches or the target’s own policy.
CloakBrowser’s launch design is strongest when read as coordination under constraints. It gives familiar automation code a path into a custom Chromium process, carries identity facts into the layer that owns them, and uses version gates where the binary’s capabilities differ. Its trade-off is that more coherent behavior requires more state and more external assumptions. The next question is whether a reader can apply this control-flow model to a complete configuration and diagnose which link in the identity chain is responsible when the result does not match expectations.