args option, or on the command line after apostate run --. A page cannot read the command line.
When the browser refuses a value, it prints apostate: <reason> on stderr and exits with status 1. A value that is logged and ignored instead is marked as such below.
All switches
The Python and Node packages refuse a switch that starts with
--fingerprint and is not in this table, and a switch within two edits of one in it, such as --fingeprint-platform. The browser itself ignores an unknown switch, as Chromium does.
Seed and persona
--fingerprint
The seed for the whole machine. The same seed and persona give the same machine on every launch and every host. Seeds and identity explains how long a machine lasts.
-
Value. 1 to 512 bytes of printable ASCII without spaces (bytes
0x21to0x7E). The Python and Node packages also take a non-negative integer, and accept a string only when it matches[A-Za-z0-9][A-Za-z0-9._:-]*. -
Host mode.
hostpresents the real machine and composes nothing.off,false,0,disableanddisabledmean the same, in any letter case. -
Default. With
--user-data-dir=DIR, the seed stored inDIR/apostate/identity, which the first launch writes. Without it, a fresh seed from OS entropy for this launch only. -
Refused. An empty value, more than 512 bytes, or a space or other byte outside printable ASCII:
-
Refused with host mode.
--fingerprint-platform,--fingerprint-anchorand every per-field switch, because nothing is composed for them to change:--fingerprint-noise,--fingerprint-webrtc-ip,--fingerprint-webrtc-udpand--fingerprint-explainare accepted with host mode. Noise does nothing there.
--fingerprint-platform
The operating system the machine presents: windows, macos or linux. The persona decides the User-Agent, Client Hints, GPU family, fonts, voices, screen layout and system colours. Personas lists everything it covers.
- Default.
macoson a macOS host,windowson a Windows host andwindowson a Linux host. - Other values. Logged and ignored, and the host’s default persona applies. The Python and Node packages refuse any value except the three names and a few aliases, in any letter case. Both take
win,win32,darwin,macandosx. Python also takeslinux2, and Node also takesmac os,mac os xandos x.
--fingerprint-anchor
Pins the GPU family instead of letting the seed draw one. The value is a family id from GPU models:
- A persona draws only from the families of its own platform, and never draws SwiftShader. Only this switch selects SwiftShader.
-
A family from another platform is accepted.
--fingerprint-explainlists the mismatch underlimitations. -
An id that is not in the table is logged, and the launch presents the host’s values on every surface:
--fingerprint-explain
Prints the composed machine to stdout and exits with status 0 without opening a window. The report goes nowhere else. Run it with the same switches as the launch you want to check:
seed source says where the seed came from, and reproduce with is the switch that gives the same machine anywhere. Each row is one choice: layer is what decided it, evidence is where the value comes from, and a line starting with ! explains the row. The report ends with a limitations list of what this launch cannot hide or apply.
With a persistent user data directory the report also names the identity file:
With an
--apostate-profile that describes a device, --fingerprint-explain prints nothing in 0.4.3 and the browser starts as normal.Per-field switches
Each switch sets one value. The seed still draws everything else, so the machine stays consistent around the value you set.
GPU strings. Either switch narrows the seed’s choice to the matching models of the family the launch uses, so the WebGL and WebGPU values still belong to that GPU. A string from another family is refused, and the error lists the models the family has:
--fingerprint-anchor with that family’s id. GPU models lists every vendor and renderer string.
Cores and memory. A persona never claims more than the host has. Asking for more is refused:
apostate: --fingerprint-device-memory='0' is not a whole number between 1 and 4096. Chromium rounds the memory a page sees in navigator.deviceMemory to 2, 4, 8, 16 or 32.
Screen. Width and height are independent. With only one of them set, the seed’s value stays for the other. The available area (availWidth, availHeight) is worked out from the size and the persona’s taskbar or menu bar. The screen is refused when it is smaller than --window-size or too small for the taskbar:
--fingerprint-explain marks each overridden value and names the value the seed had drawn.
Locale and timezone
The seed never draws the locale or the timezone. The Python and Node packages fill both switches from a GeoIP lookup of the connection’s exit unless you passlocale and timezone. Locale and timezone covers the lookup and what each value changes.
--fingerprint-locale
- One tag, such as
de-DE, sets the browser’s UI locale.Intl, date and number formats andnavigator.languagefollow it.navigator.languagesand theAccept-Languageheader carry Chrome’s own default list for that locale, such asde-DE,de,en-US,enforde-DE. - A comma list, such as
de-DE,de, setsnavigator.languagesandAccept-Languageexactly. Its first tag is the UI locale. - Default.
en-US, never the host’s language. Host mode keeps the host’s. - The browser writes the UI locale into
LANGUAGE,LC_ALL,LC_MESSAGESandLANGbefore it starts any other process.--langhas no effect on a persona. - The speech voices follow the first tag. A Windows persona lists its
en-GBvoice set foren-GBand itsen-USset for every other tag.
--fingerprint-timezone
An IANA timezone name, such as Europe/Berlin. Intl, Date and the timezone a page reads follow it.
- Default. The host’s timezone. Behind a proxy that is the host’s timezone and not the exit’s.
- An unknown name is logged as
apostate: unknown timezone 'Mars/Olympus'; keeping the host zone, and the host’s timezone stays. - The Python and Node packages also write the value into
TZ. From 0.4.4 they refuse a name that is not an IANA zone before launch, with the message in Errors. In 0.4.3 an unknown name went intoTZ, and a page’sIntltimezone readundefined.
WebRTC
WebRTC explains what these do to calls and how to check for leaks.--fingerprint-webrtc-ip
An IP address written into the host and server-reflexive ICE candidates in place of the real address. The browser does not check the value. Packets still leave from the real socket, so a peer can read the real source address off the packets it receives.
Behind a proxy, the Node package passes the exit address from its GeoIP lookup as this switch. The Python package does not.
--fingerprint-webrtc-udp
Where WebRTC’s UDP traffic goes.
Any other value is logged and treated as
block.
Readback noise
--fingerprint-noise
Changes canvas and WebGL pixel readback by at most one step per colour channel, on pixels at colour edges, so two personas on one host give different canvas hashes. Solid areas and alpha stay as rendered. The change depends only on the profile and the pixels, so the same seed reads back the same bytes every time, and getImageData, toDataURL, toBlob, convertToBlob and WebGL readPixels agree with each other.
- Default. Off. It does nothing in host mode.
- Value. None. The browser checks only whether the switch is present, so
--fingerprint-noise=falseturns noise on. The Python and Node packages refusefalse,0,no,off,disableanddisabledas its value. - A page can detect the change, for example by drawing one image at two scales and comparing them. Leave it off unless canvas hashes must differ between personas on one host.
A profile you wrote
--apostate-profile
Runs a profile you wrote instead of composing one. The value is the profile JSON, base64-encoded. Profile schema lists every field, and Custom profiles shows how to write one.
- Only the sections the profile includes change. Every other value is the host’s.
-
--fingerprint,--fingerprint-platform,--fingerprint-anchorand the per-field switches have no effect, and the browser logs which ones it ignored. The Python and Node packages refuse a profile together with--fingerprintinargs. -
A value that does not decode is refused:
Precedence
Strongest first:--apostate-profiledescribing a device: your profile, nothing composed.--fingerprint=host: the real machine, nothing composed.- Per-field switches: one value each, on top of the seed’s machine.
--fingerprint=SEED.- The seed in
DIR/apostate/identity, when--user-data-dir=DIRis set. - A fresh seed from OS entropy.
--fingerprint-platform and --fingerprint-anchor choose the persona and GPU family that the seed composes, at levels 3 to 6. Host mode refuses them and every per-field switch rather than ranking above them.
Chromium switches that matter
Launching the browser with
--enable-automation, --headless, --remote-debugging-pipe or --remote-debugging-port leaves navigator.webdriver false.
The proxy credential
Stock Chromium rejects a credential in--proxy-server. Apostate takes it off the switch before Chromium parses it, holds it in memory for the launch, and answers the proxy’s authentication with it. It does not appear in NetLog, error messages, chrome://version or --fingerprint-explain. Child processes receive it inside their --apostate-profile value, so ps on the host shows it base64-encoded.
-
Schemes that take a credential are
http,https,socks4andsocks5, and a barehost:port, which means HTTP. Usesocks5://, which already resolves names on the proxy.socks5h://is refused with a credential. -
Percent-encode
/,%and spaces in the credential (%2F,%25,%20). -
Refused: a credential on
direct://,quic://orsocks5h://, a malformed percent escape, a NUL byte, invalid UTF-8, a username or password over 4096 bytes, two proxies with different credentials, and a credential in both the URL and--apostate-profile. For example:
proxy option and the GeoIP lookup through the proxy.