Skip to main content
Apostate comes in two parts: a package for your language, and the browser, which the package downloads and checks. Quickstart is the short path. This page covers every other way to install.

Requirements

The browser runs on four hosts: There is no build for Intel Macs or 32-bit Windows. The packages’ install path on Windows has only been tested against a test archive. The Linux archives are .tar.zst. The Python package reads them with Python 3.14 or later, the zstandard Python package, or the zstd command. The Node package needs the zstd command or a tar that accepts --zstd.

Install the package

Both install Patchright, the driver the packages launch the browser with. To use Playwright instead, install it next to the package (pip install "apostate[playwright]", or npm install playwright) and pass the driver option. Detection explains why Patchright is the default. Do not run playwright install or patchright install. They download Playwright’s own Chromium, which Apostate never runs.

Download the browser

The first launch downloads the browser. To do it ahead of time:
install picks the archive for this host, downloads it from the GitHub release the package names, checks its SHA-256 before opening it, extracts the whole tree into the cache, adds the Widevine module, and prints the browser’s path. A second run finds the install and downloads nothing. Both packages install a command named apostate. If both are installed, the one first on your PATH answers; python3 -m apostate always runs the Python one. Both use the same cache, so installing with one serves the other. CLI lists every command.

The cache

APOSTATE_CACHE_DIR, the cache_dir option (Node: cacheDir) and --cache-dir override it. Inside it:
Each launch hashes the browser executable and compares it with install.json. If they differ, or the package pins a different archive, the next launch installs again.

Use a browser you already have

A launch looks for the browser in four places, in this order, and takes the first that answers: A path you name, in either of the first two, can be the executable, a macOS Chromium.app bundle, or the directory the archive unpacks to, such as apostate-152.0.7977.83-linux-x64/. The package takes the first two at your word. It refuses a path that names nothing with does not name a file, and a directory with no browser inside with names a directory with no browser inside it (expected Chromium.app, chrome or chrome.exe). The well-known search never adopts a stock Chrome or Chromium. A candidate counts only if build/MANIFEST.lock with this build’s patch digests, or resources/profiles/catalogue.json, sits beside it, and its version is 152.0.7977.83. To have an archive you extracted by hand found, move the whole extracted directory into a well-known location, not only the browser out of it. apostate info prints what the search found and what it passed over, under discovery, with a reason for each rejected candidate. In code, discovery_report() (Node: discoveryReport()) returns the same.

Mirrors

To fetch archives from your own server, set APOSTATE_DOWNLOAD_BASE_URL to the directory that holds them, with the release’s file names:
The digest never comes from the mirror. It comes from the manifest inside the package, so a mirror that serves different bytes fails the check and nothing is installed.

Offline installs

On a host with no internet access, use one of these:
  • Copy the cache. Run apostate install on a connected machine of the same platform, copy its whole cache directory to the offline host, and point APOSTATE_CACHE_DIR at it, or put it at the default path. The copy carries the Widevine module.
  • Unpack the archive. Download the archive and its .manifest.json from the release page, compare shasum -a 256 of the archive with the manifest’s sha256, and extract it on the offline host. Then set APOSTATE_BINARY to the extracted directory, or move that directory into a well-known location.
Without network access and without a copied cache, the package cannot fetch Widevine unless Google Chrome is installed on the host. The browser then launches without DRM and prints one warning. Widevine covers installing a module you copied.

Verify a download

Both packages hash the whole archive and compare it with a manifest’s sha256 before extracting anything. A mismatch stops the install, and the package opens nothing. Where the digest came from decides what the check proves, and apostate info reports it:
A package fetches a manifest only when its own does not list the archive, and it says so on stderr before downloading. A fetched digest comes from the same place as the archive, so it cannot catch a replaced one. To check where an archive came from, verify its GitHub build-provenance attestation. Keep the archive when you install, then verify it with the GitHub CLI:
The kept archive is in the cache, beside install/. APOSTATE_KEEP_ARCHIVE=1 keeps it on every install.

macOS signing

Releases since v0.2.0 are signed with a Developer ID, notarized and stapled, so a bundle downloaded with a web browser opens without a Gatekeeper prompt. To check a bundle:
spctl prints accepted and source=Notarized Developer ID, stapler prints The validate action worked!, and codesign lists the Developer ID authority and Notarization Ticket=stapled.

Update

The next launch, or apostate install, installs the archive the new package pins. A new Chromium version installs beside the old one in the cache. A seed keeps its machine across Chrome updates. A release that changes the catalogue tables can move it. Seeds and identity explains how to check before you upgrade, and the changelog lists what each release changed.

Remove

clear deletes the whole cache directory, every installed version and the Widevine module included. Then uninstall the package with pip uninstall apostate or npm uninstall @heretic-tech/apostate. Fonts that apostate fonts install added stay in ~/.local/share/fonts/apostate-* on Linux and ~/Library/Fonts/apostate-* on macOS; delete those directories to remove them.