Metadata-Version: 2.5
Name: ant0-browser
Version: 0.1.0
Summary: Local Playwright launcher for the Ant0 Browser research build.
Project-URL: Homepage, https://docs.ant0.link/sdk
Project-URL: Support, https://ant0.link/contact
License: BSD-3-Clause
License-File: LICENSE
Keywords: ant0-browser,anti-detect,anti-fingerprint,automation,chromium,farbling,fingerprint,playwright,stealth,ungoogled
Requires-Python: >=3.9
Requires-Dist: maxminddb>=2.2
Requires-Dist: playwright>=1.40
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
Requires-Dist: pytest>=7; extra == 'test'
Description-Content-Type: text/markdown

# Ant0 Browser Python SDK

Local Playwright launcher for a caller-supplied Ant0 Browser build. This package contains Python
SDK code, **not the engine**, browser assets, or account credentials. The SDK code is BSD-3-Clause
licensed; using the engine requires a separately installed Ant0 Browser build and signing in with a
valid Ant0 licence. Native identity needs no synthetic assets; synthetic identities require separately
authorized local model/template assets.

Once version `0.1.0` is available from PyPI, install it with `python -m pip install ant0-browser==0.1.0`.
For local candidate installs, use `ant0_browser-0.1.0-py3-none-any.whl` or
`ant0_browser-0.1.0.tar.gz`; these filenames do not indicate registry availability.

## Local package preparation and installation

Prerequisites: Python with `venv` and pip, and access to the package index for build/runtime
dependencies. Metadata declares Python 3.9+; this local qualification used Python 3.12, not every
supported interpreter. pip installs `playwright>=1.40` and `maxminddb>=2.2`. An unsupported platform
may need a compiler to build dependencies when their wheels are unavailable. Do not run
`playwright install`: it would download stock browser binaries, not Ant0's engine.

From the repository root, build both `0.1.0` candidate artifacts without publishing:

```bash
SDK_SOURCE="$PWD/sdk/python"
ARTIFACT_DIR="$HOME/ant0-sdk-artifacts"
mkdir -p "$ARTIFACT_DIR"
python3 -m venv "$ARTIFACT_DIR/build-venv"
"$ARTIFACT_DIR/build-venv/bin/python" -m pip install build
"$ARTIFACT_DIR/build-venv/bin/python" -m build --outdir "$ARTIFACT_DIR" "$SDK_SOURCE"
```

The candidate filenames are `ant0_browser-0.1.0-py3-none-any.whl` and
`ant0_browser-0.1.0.tar.gz`. Install each into its own fresh consumer venv outside the checkout,
not as an editable/source install:

```bash
CONSUMER_DIR="$(mktemp -d)"
cd "$CONSUMER_DIR"
python3 -m venv wheel-venv
python3 -m venv sdist-venv
wheel-venv/bin/python -m pip install "$ARTIFACT_DIR/ant0_browser-0.1.0-py3-none-any.whl"
sdist-venv/bin/python -m pip install "$ARTIFACT_DIR/ant0_browser-0.1.0.tar.gz"
```

Optional installed-package qualification (no engine launch, daemon discovery, or account access):
copy the committed smoke script into that consumer. Isolated Python ignores checkout/PYTHONPATH
imports; run deterministic sync/async checks and console help in both environments:

```bash
cp "$SDK_SOURCE/scripts/installed_smoke.py" .
for VENV in wheel-venv sdist-venv; do
  "$VENV/bin/python" -I installed_smoke.py
  "$VENV/bin/python" -m pip check
  "$VENV/bin/ant0-browser-serve" --help
done
```

These examples use POSIX venv paths; on Windows use `Scripts/python.exe` and
`Scripts/ant0-browser-serve.exe`. Remove only the temporary consumer/build venv you created when
finished. These checks qualify package contents and deterministic SDK operations, not engine
launches or registry availability.

## Using a separately installed engine

For current signed releases, first install Ant0 and sign in to the local `ant0d` with a valid
licence. Supply the complete matching Ant0 engine installation via `executable_path` or
`ANT0_BROWSER_BINARY`; arbitrary stock Chrome/Chromium is rejected by the SDK's capability check.
The daemon must issue a launch ticket for that **exact engine release version**, not the SDK package
version. See Launch ticket below. Setting `launch_ticket=False` does not bypass engine enforcement.
New synthetic identities additionally require authorized local model/template assets; the package
contains neither. The following native-mode example needs no synthetic assets:

```python
from ant0browser import launch

browser = launch(
    executable_path=r"C:\path\to\chrome.exe",
    identity={"mode": "native"},
)
page = browser.new_page()
page.goto("https://example.com")
browser.close()
```

Set `ANT0_BROWSER_BINARY` instead of passing `executable_path` on every call. A previously populated
cache is resolved without network access. If no local binary is found, the SDK stops with
instructions to build the browser and set its path, unless `ANT0_BROWSER_RELEASE_URL` points at a
release store: then the SDK installs the channel's release after verifying its minisign signature
and hashes against the key embedded in the SDK (see `docs/RELEASING.md`).

The async API mirrors launch and persistent contexts:

```python
from ant0browser.async_api import launch

browser = await launch(executable_path="/path/to/chrome", identity={"mode": "native"})
```

Retained helpers include:

- `launch()` and `launch_persistent_context()`
- `serve()` and the `ant0-browser-serve` local CDP command
- native, captured, and persisted synthetic identities
- canonical template loading via `ANT0_BROWSER_TEMPLATE_SOURCE`
- fingerprint-profile encoding, geometry and coherence warnings
- humanized input wrappers and rendering checks
- optional GeoIP (Ant0's `ip.ant0.link` + offline database, see Network calls) and Widevine helpers

Omitting `identity` means native mode. The removed `fingerprint`, `fingerprint_profile`,
`light_stealth`, `profile`, `profile_select`, and `geoip` launch options are rejected. Use
`resolve_geo()` explicitly when needed and place its identity values under `overrides`. Explicit identity
switches belong under `overrides`; supported keys are `platform`, `platform_version`, `brand`,
`brand_version`, `gpu_vendor`, `gpu_renderer`, hardware/display fields, `location`, `timezone`,
`accept_language`, WebRTC/GPU/noise controls, `storage_quota`, `canvas_bridge`, and `tls_profile`.
Overrides take precedence over captured or synthetic profiles.

The SDK resolves browser binaries and identity templates locally by default. Automatic launch-ticket
requests go only to the local daemon; optional asset/release and GeoIP requests are listed below.

## Network calls

Nothing in `launch`/`serve` leaves the machine on its own: the only automatic request is to the
**local** `ant0d` for a launch ticket (loopback, see the first row). The optional helpers do, and only when
called:

| Helper | Endpoint | Purpose |
| --- | --- | --- |
| `launch()` / `serve()` | local `ant0d` only (`ANT0_URL`, else `ant0d.pid`/`ant0d.token` under `ANT0_HOME`/the platform data folder; loopback) | `GET /v1/licence/ticket?engine=<version>` to obtain the engine's launch ticket when the caller passed no `launch_ticket` (see below). Skipped when no daemon token exists, when `launch_ticket=False`, or when the binary is not an installed release. |
| `resolve_geo()` | `http://ip.ant0.link/` (then `https://ip.ant0.link/`; `api.ipify.org` and `ip-api.com` only if both fail) | Exit-IP echo, sent *through the configured HTTP proxy* so the proxy's exit is measured. Ant0's echo runs with zero request logging (`ant0-infra/ipecho`). |
| `resolve_geo()` | `https://releases.ant0.link/ant0-assets/geoip/v1/geoip-aio-all.mmdb.zip` | Offline geo database (~52 MB, cached in the SDK cache dir for 30 days), fetched directly, not through the proxy. Mirror of daijro/geoip-all-in-one. |
| `resolve_geo()` | `http://ip.ant0.link/json` | Geo for the exit IP computed server-side from the same database; used only when the local database is unavailable. |
| release install | `ANT0_BROWSER_RELEASE_URL` (opt-in) | Signed engine releases. |
| font pack / model | `ANT0_BROWSER_FONT_PACK_URL`, `ANT0_BROWSER_MODEL_SOURCE`, `ANT0_BROWSER_TEMPLATE_SOURCE` (opt-in) | Assets. |

Overrides: `ANT0_BROWSER_IPECHO_URL`, `ANT0_BROWSER_GEOIP_URL`, `ANT0_BROWSER_GEOJSON_URL` (read at call time). Set `ANT0_BROWSER_IPECHO_URL` to disable the third-party
last-resort echoes entirely (only the given URL is tried).

Geo data attribution (required by the sources merged into geoip-all-in-one, GPL-3.0): this product
uses the IP2Location LITE database for IP geolocation (https://lite.ip2location.com); includes
GeoLite2 data created by MaxMind, available from https://www.maxmind.com/; IP geolocation by DB-IP
(https://db-ip.com). The database carries country, coordinates and timezone only.

## Launch ticket (engine patch 0037)

Engine releases built with patch `0037-launch-ticket` refuse to start without
`--ant0-launch=<ticket>`: a licence token from the Ant0 server plus a 15-minute claim signed by the
local device key, bound to the engine's release version (`ant0/docs/PHASE3-CONTRACT.md` §10). The
SDK cannot mint one; it resolves the switch like this:

1. `launch_ticket="<lic.claim.csig>"` — passed through verbatim.
2. `--ant0-launch=` already in `args` — kept.
3. Otherwise, when a local daemon is reachable (see the table above) and the engine's release version
   is known (`.release.json` next to the install's `browser/`, a `<version>/browser/` path, or
   `ANT0_BROWSER_ENGINE_VERSION`), the SDK fetches one. `engine_version=` overrides the inference.
4. Else (`launch_ticket=False`, no daemon, daemon refuses, bare binary) the launch proceeds without
   the switch. A patched engine then exits with code 90 and `ant0: launch ticket invalid (<reason>)`
   on stderr, which `launch()`, `launch_persistent_context()`, the async API and `serve()` surface as
   `LaunchTicketRejectedError` (`code == "engine.launch_ticket_rejected"`, `reason` as printed by
   the engine: `missing`, `unknown_kid`, `wrong_engine`, `claim_expired`, ...). Pre-0037 engines
   ignore the switch.

## Known engine behaviours

- **Profile portability is not a Chromium launch mode.** The removed `portable_profile` and
  `encryption_key` options did not provide supported engine portability. Cross-machine sync must use
  authenticated encrypted Ant0 bundles of logical profile data, not copied raw user-data directories
  or Chromium portability flags.
- **No SOCKS5 username/password authentication.** The engine has no RFC 1929 client (stock Chromium
  has none and no Ant0 patch adds one), and Playwright rejects credentials in a SOCKS proxy
  descriptor. `launch()`, `launch_persistent_context()` and `serve()` therefore raise `ValueError`
  on a `socks*://` proxy with `username`/`password`. Use an `http(s)://` proxy with credentials
  (Playwright handles those), a SOCKS5 proxy that allows your client IP without credentials, or a
  local relay that authenticates upstream (the `ant0d` daemon runs one per session) and pass its
  unauthenticated loopback address.
- **Direct launches show the ungoogled first-run page without hygiene switches.** Playwright's
  `launch()` passes `--no-first-run`, `--no-default-browser-check` and
  `--disable-search-engine-choice-screen` itself; a binary spawned directly with none of them opens
  `chrome://ungoogled-first-run` ("ungoogled-chromium first run page", empty body) in the first tab
  when no start URL is given. `serve()` adds those three switches (plain UI
  switches, no `base::Feature` toggles, so nothing a page can observe changes and the identity
  layer's feature flags are untouched) and append `about:blank` as the final positional when `args`
  carries no URL, so the first tab is neutral. A caller URL in `args` suppresses the `about:blank`.

## Source development and verification

From the repository root of an authorized private checkout, use a development venv with the test
extra installed. This editable install is for source tests, not installed-artifact qualification:

```bash
python3 -m venv "$ARTIFACT_DIR/test-venv"
"$ARTIFACT_DIR/test-venv/bin/python" -m pip install -e './sdk/python[test]'
PYTHONDONTWRITEBYTECODE=1 "$ARTIFACT_DIR/test-venv/bin/python" -m pytest -p no:cacheprovider sdk/python/tests
```

Leave `ANT0_BROWSER_TEST_BINARY` unset for the engine-free suite; the real-engine serve test is
opt-in and excluded from this package qualification.
