> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apostate.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> What changed in each Apostate release, newest first.

Each release publishes browser archives for Linux x64, Linux arm64, macOS arm64 and Windows x64 on [GitHub Releases](https://github.com/heretic-tech/apostate/releases). Every release so far is built on Chromium 152.0.7977.83. The Python package (`apostate` on PyPI) and the Node package (`@heretic-tech/apostate` on npm) are released with the same version number when their code changes.

## Unreleased

Changes on `main` since v0.4.3. The Python and Node packages will ship them as 0.4.4. No browser patch changed.

* **Node 22.** The Node package needs Node 22 or later, and its `engines` field says so. It calls `Promise.withResolvers`, which Node 20 lacks, so on Node 20 every GeoIP lookup of 0.4.3 failed.
* **Dark themes.** Both packages turn off Playwright's `prefers-color-scheme: light` emulation, so a page reads the persona's own theme. On 0.4.3, pass `color_scheme="null"` in Python or call `page.emulateMedia({ colorScheme: null })` in Node. See [prefers-color-scheme in the 0.4.3 packages](/known-gaps#prefers-color-scheme-in-the-0-4-3-packages).
* **Timezones.** Both packages refuse a `timezone` that is not an IANA zone name, before launch. Python raises `ConfigurationError` and Node throws `RangeError`. In 0.4.3 an unknown name went into `TZ`, and a page's `Intl` timezone read `undefined`.
* **GeoIP warning.** The warning for a failed lookup says the persona uses `en-US` and the host's timezone. In 0.4.3 it said the launch keeps the host's own locale, which was wrong. The reason and the advice are joined without a double period.
* **Python diagnostics.** Python launches carry `apostate_diagnostics`, as Node launches carry `apostateDiagnostics`. GeoIP warnings are in its `["warnings"]` list.
* **Python sync API.** Several browsers can be open at once in one thread. They share the thread's driver, which stops when the last of them closes. In 0.4.3 a second `launch()` while one is open fails with `Sync API inside the asyncio loop`.
* **Launch errors.** A launch error no longer carries the `--apostate-profile` value, which holds a proxy credential base64-encoded. The value reads `--apostate-profile=<redacted>`. In Python, a proxy URL in the error text has its credential replaced with `<redacted>`, and the rest of the text is kept. In 0.4.3 the text was cut at the first proxy URL, which dropped the browser's own `apostate:` refusal line.
* **Sandbox.** Both packages keep Chromium's sandbox on where it can start: macOS, Windows, and Linux as a regular user outside a container, with no seccomp filter and with user namespaces allowed. Playwright otherwise passes `--no-sandbox`, and a headed window then shows Chromium's unsupported-flag bar on its first tab, which took 56 pixels from `innerHeight`. An explicit `chromium_sandbox` or `chromiumSandbox` is kept. See [A bar on the first tab](/known-gaps#a-bar-on-the-first-tab).
* **Proxy credentials.** Both packages count the 4096 limit for a username or password in bytes of UTF-8, as the browser does, and both refuse a malformed escape such as `%zz`.
* **Timezone case.** The Node package refuses a timezone that differs from a zone name only in letter case, such as `europe/berlin`, as the Python package does. On Windows the Python package depends on `tzdata`, so it can check names on a host with no tz database.
* **Node first run.** Every Node launch passes `--no-first-run` and `--no-default-browser-check`. `launchProcess()` did not, so a headed first launch of a new user data directory could stop at a first-run dialog.
* **Python CLI.** `apostate run` forwards every argument after `run` to the browser, so `apostate run --fingerprint=42` works without a `--` separator, as it already did in the Node CLI.
* **Fonts.** `apostate fonts install windows` also installs the Windows 11 Marlett, which the font repository it clones lacks. It reads only that file out of the `liblaf/fonts` Win11 release zip with HTTP range requests, and installs it only when its SHA-256 matches.
* **Catalogue.** The catalogue the packages ship describes the seed as keyed on the version values v0.4.2 used, and names `apostate/identity` as the file a persistent profile stores its seed in. The browser's own catalogue is unchanged.
* **MCP server.** A new package in `mcp/`, `@heretic-tech/apostate-mcp` 0.1.0, gives an AI agent an Apostate browser with Playwright MCP's tools. It needs Node 22 or later. [MCP server](/agents/mcp) describes it.
* **Test suite.** `tests/` checks what a page reads from the browser, offline against a local probe page and live against public detector pages, and writes each run to a dated results file. The offline tier and the MCP server's test run in CI on Linux x64 with the released browser. [Test suite](/testing/overview) describes it, and [Results](/testing/results) has the published runs from macOS arm64 and Linux arm64.
* **Examples.** `examples/` holds runnable Python, Node, use-case, agent and Docker examples. [Examples](/examples) lists them.
* **Documentation.** This site replaces the Markdown pages in `docs/`. `docs/KNOWN_GAPS.md` stays as a pointer, because the 0.4.3 browser's `--fingerprint-explain` names it. The repository README and the PyPI and npm READMEs link to the site.

## v0.4.3

Released 26 September 2026. Python and Node packages 0.4.3.

* **URLs.** A Windows persona parses file paths in URLs as Windows Chrome does. `new URL("c:/foo").protocol` is `file:`, where other personas and stock Chromium on Linux and macOS give `c:`.
* **Seeds.** A seed keeps its machine across Chrome updates and catalogue version changes. The machine is keyed on fixed version values, the ones v0.4.2 used, so a v0.4.2 seed presents the same machine in v0.4.3. An edit to a catalogue table still re-draws the choices that table decides.
* **CPU performance.** `navigator.cpuPerformance` follows the persona's core count and ignores the host's CPU model, except for a macOS persona on a Mac.
* **Python.** `viewport=None` means no viewport. Playwright had dropped the `None` and emulated a 1280x720 viewport.

## v0.4.2

Released 25 September 2026. Browser archives only. No package was released at this version.

* **Fonts under a Windows persona.** Ascent, descent and line gap come from the fonts' Windows metrics as DirectWrite reads them, including the typo metrics a font asks for. Windows alias and legacy family names resolve, such as Courier, Times, Helvetica, MS Sans Serif and Franklin Gothic. Emoji and symbols fall back to Segoe UI Emoji, Segoe UI Symbol and Cambria Math.
* **Font install.** `apostate fonts install windows` installs only the families of the Windows core font pack, lists the ones still missing, and takes `--from DIR` to install from a Windows `Fonts` folder.
* **Locale.** `--fingerprint-locale` with one tag sets only the UI locale, and the language list is Chrome's own default for that locale. A comma list sets the list exactly. The packages pass the GeoIP locale as one tag.
* **Voices.** A persona lists its voices on a host with no speech engine. The Windows sets include the Google network voices desktop Chrome lists, and the en-US Windows set matches two real machines' 22 voices.
* **WebGPU.** `GPUAdapterInfo.subgroupMinSize` and `subgroupMaxSize` come from the GPU family instead of the host.
* **Window.** A new window fills the persona's work area, and a Windows persona opens maximized. The packages' Xvfb display is 3840x2160, so any claimed screen fits.
* **Windows machines.** Screen sizes and core counts follow a public corpus of Windows sessions. The taskbar is at the bottom, 40 pixels on Windows 10 and 48 on Windows 11. The 1920x1200 and 2048x1280 screens are gone, and the network is always `4g`. These table changes give many seeds a different machine than v0.4.0 gave them.
* **Linux personas on ARM hosts** keep `navigator.platform` as `Linux x86_64`, as Chrome does on every Linux CPU. The ARM host shows only in the Client Hints architecture.

## v0.4.0

Released 23 September 2026. Python and Node packages 0.4.0.

* **Normal profile.** `launch()` opens pages in a normal profile instead of an off-the-record context, on a temporary profile the driver deletes on close. `new_context()` stays off-the-record, as in Playwright. This needs Patchright 1.55 or Playwright 1.53 or later.
* **Windows system values.** A Windows persona serves Windows system colours, Segoe UI for the CSS system fonts, Windows' `system-ui` and default fonts, no `BarcodeDetector`, a 48 kHz `AudioContext`, the claimed speakers on a host with no sound card, the claimed GPU's power-efficient codecs and the US Windows keyboard map.
* **CPU architecture.** Windows and Linux personas claim the host's CPU architecture, `arm` on an ARM host.
* **WebGPU.** A host with no GPU serves the claimed adapter instead of none, and every GPU model has a WebGPU adapter. On Linux, `requestAdapter()` still returns null in headless mode and in a headed launch as root. See [WebGPU in headless mode on Linux](/known-gaps#webgpu-in-headless-mode-on-linux).
* **Widevine.** The packages give the browser a Widevine CDM on first launch, copied from a local Google Chrome or downloaded from Google and checked by SHA-256. The Python CLI adds `apostate provision-drm`.
* **Linux displays.** A headed launch on a Linux host with no display starts its own Xvfb, sized to the persona's screen, and stops it on close.
* **Fonts.** Each persona shows only its platform's font families. The CLI adds `apostate fonts install windows`, `fonts install macos` and `fonts export-macos`.
* **Removed.** The font metric and text raster emulation added in earlier releases, which measured as changing nothing detectors score.
* **Fixes.** A Windows persona no longer crashes the browser in `enumerateDevices()` on a host with no sound card. WebGPU on a host with no GPU keeps the `float32-filterable` and `float32-blendable` features. The Python package extracts `.tar.zst` on Python before 3.14, and the Node package decompresses zstd itself on Node 22.15 and later.

## v0.3.0

Released 22 September 2026. Python and Node packages 0.3.0.

* **Windows fonts and voices.** The Windows core font pack is the Windows 11 English set, and every persona lists its own platform's voices, spoken by a real speech provider.
* **Refused switches.** Both packages refuse a misspelt `--fingerprint*` switch, such as `--fingeprint-platform`, and `--fingerprint-noise=false`, which turns noise on.
* **Persistent profiles.** Both packages refuse a persistent profile on `launch()` and name `launch_persistent_context()` instead. The Node package also refuses `--user-data-dir` and `--proxy-server` in `args`, which it had dropped without a word.
* **GeoIP through SOCKS5.** The lookup hands the endpoint's name to the proxy instead of resolving it on the host.
* **Node package.** It downloads from its own release, and an extraction failure names the tool that is missing.

## v0.2.1

Released 22 September 2026. Python and Node packages 0.2.1.

* **Text.** A persona derives sub-pixel text positioning by its own platform's rule, so a Linux persona on a Mac measures text advances as Linux Chrome does.

## v0.2.0

Released 21 September 2026. Node package 0.2.0.

* **Signed macOS build.** The macOS bundle is Developer ID signed and notarized.
* **GPUs.** A Windows persona can present many more NVIDIA and Intel models, registered on the measured GPU families by PCI device id, including the GeForce RTX 40 series.
* **WebGL.** The GPU family's WebGL limits reach pages on every host backend, Metal included.
* **WebRTC.** Behind a SOCKS5 proxy, WebRTC offers only the address families the proxy can relay.
* **Readback noise.** `--fingerprint-noise`, off by default, changes canvas and WebGL readback by one step per channel, seeded by the profile.
* **Extensions.** The profile decides whether pages see `chrome.runtime` from an installed extension.
* **Install.** Patchright is a dependency of both packages, so one install is enough. The packages find a browser already on disk before downloading one.

## v0.1.0

Released 20 September 2026. Python and Node packages 0.1.0, and 0.1.1.

The first public release. It is Chromium 152.0.7977.83 with a composer that builds a whole Windows, macOS or Linux machine from a seed before any other browser process starts.

* **Switches.** `--fingerprint`, `--fingerprint-platform`, `--fingerprint-anchor` and `--fingerprint-explain`, the per-field switches, `--fingerprint=host` and `--apostate-profile`.
* **Persistent identity.** A launch with `--user-data-dir` stores its seed in the directory and presents the same machine on every later launch.
* **Locale and timezone.** They come from the launch or the host, never from the seed. A composed persona ignores the shell's locale.
* **Proxies.** `--proxy-server` accepts a credential in the URL. WebRTC relays UDP through a SOCKS5 proxy or opens no UDP socket.
* **Packages.** The Python and Node packages download and verify the browser, look up the exit's locale and timezone, and launch it through Patchright or Playwright. The Node package also drives Puppeteer.

The 0.1.1 packages install the v0.1.0 browser. They fetch the release's manifest when the package carries none, ship the GeoIP lookup inside the Python package with SOCKS5 support, map every country to a locale, and send a SOCKS proxy credential to the browser instead of the driver.
