Weles/Docs

Concept

A coherent persona for every browsing context.

A fingerprint profile is the combination of browser engine, persona OS, locale, and patched browser build presented to a target site. Weles rotates fingerprints to stop agents running into CAPTCHAs and bans.

What composes a profile#

Profile inputs on the weles CLI (defaults from weles --help, weles 0.7.56)
InputDefaultEffect
--browser <name>(required)Engine passed to AsyncNewBrowser; chromium or firefox.
--os <name>(required)Persona OS passed to AsyncNewBrowser; macos, windows or linux.
--locale <locale>(unset)Locale passed to AsyncNewBrowser.
--proxy <url>(unset)Proxy server URL for the browsing context.

Where a persona's locale and device come from#

A persona's timezone and language follow the country its browser exits through, because a locale that disagrees with the exit is the mismatch fraud checks look for. A launched session samples its device first, resolves its proxy with it, and then takes the country and timezone the proxy exit reported (its observed exit geography), else the country the proxy was resolved for. An account session takes the country of the proxy it resolved for the account. A run without a proxy exit country states one in WELES_PERSONA_COUNTRY. When the exit's timezone is not known, the persona uses the country's own.

Nothing is assumed when no country is known. A run that names none is refused with persona_country_unknown, and a country Weles holds no locale for is refused with persona_country_unsupported, which lists the countries it holds. A persona already stored for an account or browser profile keeps its locale; only a new persona is dressed this way.

The device (operating system, browser engine, screen, GPU vendor and renderer, cores and device memory) comes from one fingerprint-generator sample of a real desktop browser, so its fields are a combination real traffic carries. When the run does not force an operating system or engine, their shares are the dataset's own, among the engines Weles launches from a selected release. The run log line [persona] prints the renderer string exactly as sampled, with the country, timezone and language chosen.

The Firefox navigator surface is sampled the same way and carries the major version of the selected weles-firefox release, so the user agent agrees with the installed engine. A selected release whose version names no major is refused with persona_firefox_version_unreadable.

At launch the fingerprint is one more sample for the persona's system, engine and exact screen size, with the persona's device and locale laid over it and, when the target system is the host's (WELES_HONEST_HOST not 0), the host's real GPU, cores and memory. WELES_HONEST_SCREEN is 1 to report the host's display or 0 to report the persona's; unset, a headed browser reports the host's and a headless one does not, and any other value is refused. The window is WELES_VIEWPORT=<width>x<height>, else the persona's screen, else the host's available area, never larger than the host screen it reports.

A recorded launch writes its video at WELES_VIDEO_SIZE=<width>x<height> when stated, else at Playwright's own size (the viewport scaled to fit 800x800); a malformed size is refused. The recordings store is pruned, oldest run first, to WELES_RECORDINGS_MAX_BYTES; when that is not set nothing is pruned and the launch says so on standard error ('[recordings-prune] WELES_RECORDINGS_MAX_BYTES is not set, so the recordings store … is not pruned').

Patched builds#

The engines themselves are custom C++-patched Chromium and Firefox forks (the public wisent-ai/weles-chromium and firefox sources). They launch only when the host's local receipt matches the exact Stado release coordinate and checksum selected for the worker, so the stealth surface is pinned like everything else. Explicit browser-path overrides are refused; stock browser installation does not satisfy release admission.

The immutable worker identity uses the same browser selection as launch admission: WELES_CHROMIUM_RELEASE_VERSION with WELES_CHROMIUM_RELEASE_SHA256, and WELES_FIREFOX_RELEASE_VERSION with WELES_FIREFOX_RELEASE_SHA256. The authenticated worker version response reports these as chromium_release/chromium_sha256 and firefox_release/firefox_sha256. There is no separate browser-version override for diagnostics. The real dedicated-host keeper/API journey checks that reported identity against its selected browser coordinates before exercising launch admission and keeper lifecycle; complete release identity and actual browser installation remain separate requirements.

A browser admission refusal includes the failed operation and observed cause: an unset release version or checksum, an invalid checksum, an unsupported platform, an inaccessible executable or receipt, a non-file executable, or a receipt that differs from the selected release. File-operation failures retain their path and operating-system error. Receipt mismatches show expected and observed release metadata. Correct the deployment selection or install its exact browser release through Stado; do not substitute a different browser. This diagnostic alone does not establish that a browser was installed or authentication succeeded.

Chromium's real source-admission and archive-installation journeys require WELES_CHROMIUM_TEST_SOURCE_REVISION to match the clean product checkout before changing the dedicated source or installing the archive. Their reports retain the observed revision and commands. Installation compares the executable's browser version with browser-capabilities.json upstreamVersion, while the receipt must match the independently selected product release coordinate and archive digest. A patch release need not change Chromium's upstream version. These journeys do not substitute for artifact-bound browser navigation or the Stado Desktop release observations.

Chromium's required browser-runtime (darwin-arm64) and browser-runtime-linux (linux-amd64) release deliveries install the verified native archive at $HOME/.local/share/weles-chromium/<version> on registry-declared destinations. Darwin arm64 uses Chromium.app/Contents/MacOS/Chromium; Linux x86_64 uses chromium/chrome. A platform/host mismatch is refused before extraction. Manage placement with stado release destinations set weles-chromium --target <host> and inspect stado release status weles-chromium --json, or use the matching Stado Desktop Releases operations. Delivery verifies the archive coordinate and digest before extraction, checks the executable and writes the launch-admission receipt. It then records the verified release as the host's selection in $HOME/.local/share/weles-chromium/selected (version= and sha256= lines, replaced whole), and the Weles service launcher exports that record as WELES_CHROMIUM_RELEASE_VERSION and WELES_CHROMIUM_RELEASE_SHA256 at its next start; a missing or malformed record is named in the Weles log, and browser runs are refused with WELES_CHROMIUM_RELEASE_VERSION is not set. Repeated delivery refuses conflicting receipts rather than replacing an installed release; unsupported hosts, custom roots and concurrent installation retain specific refusals. The real archive journey in weles-chromium/tests/release/installation.rs covers foreign-platform refusal, installation, repeated delivery, checksum and receipt conflicts, reservation ownership and recovery after refusal in an isolated home on each matching dedicated host, separately from Weles browser navigation. Linux builds use upstream stable_deb packaging and its declared installation directory rather than copying only the browser executable; GN, dpkg-deb, upstream Debian build dependencies and a configured non-component, unbranded out/Weles build are required. The builder still requires its declared upstream Chromium source; a destination declaration is not a successful build or browser run.

Chromium release builds use the same patch operation as bash apply.sh /path/to/chromium/src in the weles-chromium checkout. Git and jq are required. Before applying patches, the producer also admits autoninja, the native packaging tools, the generated out/Weles/build.ninja graph and unused staging and Linux package-extraction destinations. A missing prerequisite, existing output tree or dangling destination symlink refuses before source changes. The source must name the exact Chromium checkout root and contain no uncommitted work or unfinished Git operation. Refusal names the observed state before source changes. The operation reads the declared fork point, applies the series on detached HEAD without resetting existing branches, and retains a failed patch operation rather than aborting and retrying it. The real preserves_unconfigured_build_source qualification exercises the producer refusal against an actual unconfigured checkout. The preserves_occupied_extraction_source and preserves_dangling_extraction_source journeys use configured dedicated Linux source and native packaging tools, retain before/after source and owned extraction state, and require both to remain unchanged after refusal. These source checks do not prove that a browser release was built, distributed or adopted by a worker.

Reading timing diagnostics#

The retained fingerprint.json records the clock observation method beside its samples. Weles observes browser activity rather than inserting randomized delays to manufacture a sampling interval. A hidden document or a failed observation records its actual cause in js.performance._err, not invented clock values.

Clock comparisons require matching collection methods. If a current capture and its baseline use different methods, the report records an informational finding and asks for a baseline collected with the same probe revision. It does not label that mismatch as clock interception. These observations describe the browser measurement, not proof that a website action succeeded.

Reading protocol setup results#

Session startup observes completion of its CDP byte-counter setup. Optional CDP diagnostics observe the same result instead of giving attachment an arbitrary number of event-loop turns. A setup failure names the actual operation and cause in the run log.

The retained .inst.json records cdp_attach_error. When CDP diagnostics are enabled, cdp_targets also records an attach_error event. A null setup error is not proof that every diagnostic domain worked. Inspect the relevant capture's data and failure fields; an absent measurement is not a healthy result.

Capture coverage counts actual CDP target, frame and firehose events separately from attachment errors. An attachment error alone does not make C.cdp.firehose emitted. A requested setup without events is attempted; a collector that was not requested and emitted nothing is missing.

The CDP firehose (cdp_firehose in the .inst.json, cdp_firehose_mode passive or off) records every protocol event the browser's CDP session delivers, under its domain and name, from the domains the diagnostics already enabled; it enables no domain of its own and keeps no list of protocol events. WELES_CDP_FIREHOSE set to one turns it on and set to zero turns it off; unset, it follows WELES_FULL_DIAGNOSTICS, which the worker sets for every run.

Each CDP record of the .inst.json (cdp_targets, frame events, cdp_network, webaudio, animations, indexed_db, page_events, runtime, log_entries, security and storage events) keeps the protocol event whole: its own parameters as Chrome sent them, with t (when it arrived) and phase (the record's name for it). A domain Chrome refuses to enable records nothing, and its refusal is kept as an enable_error event in cdp_targets naming the method, and on the capture's own error field (webaudio_error, animations_error, indexed_db_error, cdp_tracing_error, js_coverage_error, css_coverage_error) where it has one. CDP Tracing samples at Chrome's own default rate; WELES_CDP_TRACING set to zero turns it off.

Each session writes its .inst.json as <time>.inst.json beside its video (<time>.webm) and network.ndjson in the session's recordings directory: recordings/<run>/<label>/, or the run's own directory for an unlabelled session. A member whose collector never ran is null in the dump, never an empty list, so an absent capture does not read as one that ran and saw nothing. Each console argument is {value} when the page gave its value, or {unreadable} with the reason it could not be read. The proxy's username appears only as username_present and username_hash, the SHA-256 digest other Weles diagnostics use.

Close reports proxy_bytes=unavailable with counter_error when the counter could not be installed, rather than presenting that failure as zero traffic or recording a measured egress cost from it. Diagnostic setup completes before its collectors are stopped, and final CDP capture runs before that protocol session is detached.

Activity-driven diagnostic snapshots#

Instrumentation captures its initial state, session-page request completion or failure, navigation, document readiness, console and page errors, completed workflow steps, and close. It does not refresh the dump on five- or ten-second timers. Enabled performance, process, DOM-counter and storage measurements run at these checkpoints.

Page-side animation-frame request and event-listener registration counters are included when the access log is collected; they install no reporting timers of their own. Their values are cumulative counts at each capture, not periodic rates or proof that an animation frame was presented.

Captures are serialized. Events that arrive before a queued capture starts share that capture; events during collection form the next one. A completed step observes its own capture rather than waiting for all future browser traffic to stop. Close removes the activity listeners and completes queued captures before the final snapshot and publication.

The retained .inst.json includes last_checkpoint with its timestamp and triggering reasons, and checkpoint_errors with the failed operation, cause and observed page URL. Failures also appear in the run log. If writing the artifact itself fails, the log reports that failure; the error reaches the artifact only if a later publication succeeds. Missing frame instrumentation is an error, not a fabricated empty access log.

The DOM timeline keeps the latest 80 distinct URL-and-HTML states, including changes that preserve the HTML length. A closed or crashed page retains earlier captures and reports the premature close or crash. These snapshots describe observed state; they do not prove that a provider accepted a workflow action.

Apple-signed Firefox archives#

The Firefox producer packages a previously built macOS app with python3 -m weles_firefox package --app /path/to/Firefox.app --version 142.0a1-weles.N, from the weles-firefox checkout. Replace N with the candidate revision. The command copies the input, preserves CFBundleIdentifier, signs native code through Wisent Products, verifies the complete bundle with codesign, and only then creates the archive, checksum and release-metadata.json. It neither opens a browser nor changes the installed browser.

The builder needs an available Apple Development or Developer ID Application identity. Missing signing tools or identities remain errors; ad-hoc signing is refused. A dirty producer checkout, an incompatible Firefox version or an existing candidate output is refused. The metadata retains the producer revision, patch tree, input executable digest and Apple designated requirement. Candidate publication and browser execution keep their existing authorization and dedicated-host requirements.

Weles verifies the publisher-signed archive without replacing its code signature. It must not sign an installed checksum-selected browser in place, because that would invalidate the recorded release bytes.