# Stealth Browser Agent (`reqeique/apify-stealth-browser`) Actor

Human-like stealth browser session server on Apify RESIDENTIAL proxy — passes 7/7 bot-detection tests, snapshot-driven command API for LLM agents, live noVNC viewer, and Cloudflare-R2 persistent profiles for surviving logins across runs.

- **URL**: https://apify.com/reqeique/apify-stealth-browser.md
- **Developed by:** [Reqeique](https://apify.com/reqeique) (community)
- **Categories:** AI, Developer tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / 1,000 browser-session-seconds (or compute-unit seconds)s

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Stealth Browser Agent

**A hosted browser session that pretends to be human — and passes the tests your local scripts fail.**

It runs a source-patched Chromium (CloakBrowser) with a sticky residential IP on Apify, exposes a snapshot-driven command API for LLM agents, and ships a live noVNC viewer plus optional Cloudflare-R2 profile persistence so logins survive across runs.

***

### The Core: 100% Stealth

1. **7/7 Bot-Detection Pass** — scores green across the entire Sannysoft and rebrowser CDP passive leak-test suites.
2. **Sticky Residential IP** — pins a single residential IP per run, preventing mid-session CDN panics and 404s from rotating IPs.
3. **Human-Like Input** — Bézier cursor paths with natural speed ramps and aim jitter; per-character typing with thinking pauses. With VNC enabled these are driven through the real X11 pointer (visible in the viewer).
4. **Agent-Ready Accessibility Tree** — stable `@eN` layout selectors so your LLM never reasons about raw CSS or pixel coordinates.

***

### Modes & Inputs

| Input | Values | Default | What it does |
|---|---|---|---|
| `mode` | `server` / `batch` / `detect` | `server` | Interactive session server · one-shot batch executor · 7-test bot-detection suite |
| `backend` | `cloak` / `zendriver` | `cloak` | CloakBrowser (modified Chromium + Playwright API, humanize on) or zendriver (CDP + human mouse) |
| `vnc` | bool | `false` | Head the browser on Xvfb and serve **noVNC at `GET /vnc`** — drive multi-step logins in your own browser |
| `session_name` | string | — | Save/restore the browser profile (cookies, localStorage, logins) to **Cloudflare R2** across runs. Same name = same profile |
| `persist` | bool | auto | Pull/push the profile on start/interval/shutdown. Implied by `session_name` |
| `persist_interval_s` | int | `300` | How often the live profile is re-uploaded to R2 |
| `prox country` | ISO code | `US` | Apify RESIDENTIAL proxy country |
| `idle_timeout_s` | int | `300` | Exit after N seconds with no commands (`0` = only on `close`) |

R2 persistence is **optional**: it's a no-op when the `R2_BUCKET_NAME` /
`R2_ENDPOINT_URL` / `R2_ACCESS_KEY_ID` / `R2_SECRET_ACCESS_KEY` credentials
aren't set, so the actor runs fine with zero configuration.

#### Live noVNC viewer

With `vnc=true` the actor heads the browser and serves a viewer at:

```
https://<container-url>/vnc
```

You can click/type directly in your browser (great for CAPTCHA-only or
login-gated steps), while an agent concurrently drives the same session
through the command API.

#### Persistent profiles (R2)

Pass a `session_name` to pin a reusable profile:

- **Start** — downloads `<name>.tar.gz` from R2 (fresh profile on missing archive).
- **Every `persist_interval_s` + on shutdown** — re-uploads the profile.
- Stale Chrome lock files (`SingletonLock` etc.) from aborted runs are cleared
  before launch, so restoring an interrupted profile never crashes the browser.

***

### 1-Line CLI Client (Public)

The open-source `undercover-driver` client drives the private Apify server:

```sh
## macOS / Linux
curl -fsSL https://raw.githubusercontent.com/Reqeique/undercover-driver/main/install.sh | sh

## Windows PowerShell
irm https://raw.githubusercontent.com/Reqeique/undercover-driver/main/install.ps1 | iex
```

*Note: the CLI client is fully public (MIT); the server-side stealth engines stay private.*

#### Drive the session

```sh
export BROWSER_URL=https://<container>.runs.apify.net
export BROWSER_TOKEN=<auth_token>

undercover-driver goto https://target-protected-site.com
undercover-driver snapshot          # -> layout output with @e1..@eN targets
undercover-driver click @e3         # -> clicks via human-like Bézier path
undercover-driver verify_cf         # -> auto-solves Cloudflare Turnstile
undercover-driver vnc               # -> print the noVNC viewer URL
```

#### Zero-config: one token, no setup

With only an Apify API token, the CLI attaches to the most recent
**RUNNING** run — or starts a fresh server session and waits for it to boot:

```sh
export APIFY_TOKEN=<apify-api-token>   # the only thing you need
undercover-driver goto https://target-protected-site.com
```

Resolution order:

1. `BROWSER_URL` / `--url` — if set, used as-is.
2. Latest **RUNNING** run of the actor → its container URL.
3. Otherwise a new server session is started (`mode=server`, cloak backend,
   US residential proxy, 1 h idle timeout) and polled until ready.

The new session's `auth_token` is your CLI bearer token, so the same
`APIFY_TOKEN` resolves, starts, and authenticates the session. For
attach-only behavior, pass `--no-autostart` / `AB_NO_AUTOSTART=1`; point at a
different actor with `--actor-id` / `APIFY_ACTOR_ID`.

***

### Pricing — The Real Cost

Apify platform usage costs are passed through (at cost) with a small
session-time margin:

| Line Item | Rate | Usage |
|---|---|---|
| **browser-session-seconds** | **$0.0694 / 1,000 sec** | Session margin (~$0.25/hr) |
| Compute units | $0.20 / CU | Apify at cost (2 GB container × 1 hr = 2 CU) |
| Residential proxy | ~$8 / GB | Apify at cost (dominant line under heavy load) |

The actor runs at **2 GB** memory (measured peak 1.3 GB, median 700 MB).
Time-based cost works out to **~$0.65/hr**; only proxy traffic pushes it higher.

#### Realistic Scenarios

- **Smoke run (~1 min):** ~$0.05
- **Quick check (~10 min):** ~$0.10
- **~1 hour light session:** ~$0.65
- **Heavy hour (250 page loads, ~1 GB proxy traffic):** ~$8.65 (proxy dominates)

***

### License

**Proprietary — server-side closed source.** Run it on Apify; the core stealth code is not published.

# Actor input Schema

## `mode` (type: `string`):

'server' (default) runs the interactive session server; 'batch' runs the one-shot batch executor; 'detect' runs the 7-test bot-detection suite across both backends sequentially.

## `idle_timeout_s` (type: `integer`):

Server mode: exit the actor after this many seconds with no commands. 0 = never idle-exit (only on close).

## `auth_token` (type: `string`):

Bearer token clients must send to /command, /events, /health. Defaults to the actor's APIFY\_TOKEN.

## `proxy_country` (type: `string`):

ISO 3166-1 alpha-2 country code.

## `backend` (type: `string`):

Interactive session browser: 'cloak' (default — CloakBrowser modified Chromium + Playwright API, humanize=True, non-headless; passes 7/7 detection tests) or 'zendriver' (CDP + human mouse emulation).

## `backends` (type: `array`):

List of backends to drive through the detect suite. Default: \['zendriver','cloak']. Accepted values: 'zendriver', 'cloak'.

## `batch` (type: `array,string`):

JSONL string or array of step objects for one-shot batch mode.

## `target_url` (type: `string`):

If set and batch has no navigate, the actor navigates here first.

## `max_steps` (type: `integer`):

Safety cap on number of commands executed.

## `dry_run` (type: `boolean`):

Skip mutating commands (submit).

## `screenshot` (type: `boolean`):

Save a single PNG of the final page state.

## `twocaptcha_key` (type: `string`):

Optional key for captcha solve (default impl returns false).

## `vnc` (type: `boolean`):

Server mode: heads the browser on Xvfb and serves noVNC at GET /vnc on the session URL, so you can drive multi-step logins (e.g. Google) by hand in your own browser.

## `session_name` (type: `string`):

Server mode: name to save/restore the Chrome user-data-dir (cookies, localStorage, logins) to Cloudflare R2 across runs. Same name = same profile. Implies persist when set; set persist=false to disable.

## `persist` (type: `boolean`):

Server mode: pull/push the browser profile to/from Cloudflare R2 on start/stop+interval. Requires R2\_ENDPOINT\_URL / R2\_ACCESS\_KEY\_ID / R2\_SECRET\_ACCESS\_KEY / R2\_BUCKET\_NAME actor env vars; otherwise logs a warning and runs with a non-persistent profile.

## `persist_interval_s` (type: `integer`):

Server mode: periodic R2 backup cadence. 0 = only backup once on shutdown.

## Actor input object example

```json
{
  "mode": "server",
  "idle_timeout_s": 300,
  "proxy_country": "US",
  "backend": "cloak",
  "backends": [
    "zendriver",
    "cloak"
  ],
  "max_steps": 50,
  "dry_run": true,
  "screenshot": true,
  "vnc": false,
  "persist": false,
  "persist_interval_s": 300
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("reqeique/apify-stealth-browser").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("reqeique/apify-stealth-browser").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call reqeique/apify-stealth-browser --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,reqeique/apify-stealth-browser"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/pHO5Yrhfzq7ZCu5Fy/builds/S75N2a9uovEdc2eAs/openapi.json
