Skip to main content

Phantom

Stealth browser CLI that bypasses WAFs and bot detection. Built on Playwright with anti-detection patches so you can fetch pages that block headless browsers, curl, and wget.

Works as a CLI tool for humans and outputs structured JSON for AI agents.

Install

pip install phantom-browse

Chromium is installed automatically on first run. To install it manually:

python -m playwright install chromium

Usage

# Get page text
phantom https://example.com

# Structured JSON output (for agents)
phantom https://example.com --json

# Screenshot
phantom https://example.com --screenshot page.png

# Login flow
phantom https://app.com/login \
  --fill "input[name=email]=user@example.com" \
  --fill "input[name=password]=secret" \
  --click "button[type=submit]" \
  --session myapp \
  --json

# Reuse session (skip login next time)
phantom https://app.com/dashboard --session myapp --json

JSON Output

When using --json, Phantom returns:

{
  "ok": true,
  "url": "https://example.com",
  "title": "Example Domain",
  "text": "...",
  "screenshot": null,
  "console_errors": []
}

On failure:

{
  "ok": false,
  "url": "https://example.com",
  "error": "Navigation failed: net::ERR_NAME_NOT_RESOLVED"
}

Interaction Flags

Actions execute in order, before the final page capture.

--click SELECTOR        # Click element (coordinate-based, human-like timing)
--fill SEL=VAL          # Fill input field (instant)
--type SEL=VAL          # Type into input (80ms per-character delay)
--wait SELECTOR         # Wait for element to appear

Chain them:

phantom https://app.com \
  --wait "form" \
  --fill "input[name=q]=test" \
  --click "button[type=submit]" \
  --json

Multi-Step Plans

For complex flows (login, navigate, interact, capture), use --actions with a JSON plan file:

phantom --actions plan.json --json
phantom https://app.com --actions plan.json --session myapp --json

Plan format — array of steps, each with action, params, and optional description/critical:

[
  {"action": "goto", "params": {"url": "https://app.com/login"}, "description": "Open login page"},
  {"action": "fill", "params": {"selector": "input[name=email]", "value": "me@x.com"}},
  {"action": "fill", "params": {"selector": "input[name=password]", "value": "secret"}},
  {"action": "click", "params": {"selector": "button[type=submit]"}, "critical": true},
  {"action": "wait_for", "params": {"selector": ".dashboard"}, "critical": true},
  {"action": "screenshot", "params": {"path": "/tmp/dashboard.png"}},
  {"action": "goto", "params": {"url": "https://app.com/profile"}},
  {"action": "get_text", "params": {"selector": ".profile-info"}}
]

If a step marked critical: true fails, remaining steps are skipped.

Supported actions: goto, click, fill, type_text, wait_for, wait_for_spa_idle, screenshot, get_text, evaluate, select_option, press_key, login, assert_visible, assert_text_contains, assert_url_contains, get_element_count, get_inner_html, get_table_data

Multi-step output:

{
  "ok": true,
  "steps_total": 8,
  "steps_executed": 8,
  "steps_passed": 8,
  "aborted_at": null,
  "url": "https://app.com/profile",
  "steps": [
    {"ok": true, "action": "goto", "description": "Open login page", "url": "https://app.com/login"},
    {"ok": true, "action": "fill", "description": "fill"},
    ...
  ]
}

Options

--json              Structured JSON output
--actions FILE      JSON file with multi-step action plan
--screenshot PATH   Save full-page screenshot
--session NAME      Cookie persistence (~/.phantom/sessions/)
--timeout MS        Navigation timeout (default: 30000)
--headless          Force headless mode
--headed            Force headed mode (requires display/Xvfb)
--locale LOCALE     Browser locale (default: en-US)
--timezone TZ       Browser timezone (default: America/New_York)
--viewport W H      Viewport size (default: 1366 768)
--min-delay SECS    Min seconds between requests to same domain (default: 2.0, 0 to disable)
--verbose           Debug logging

What It Bypasses

Phantom bundles these anti-detection techniques:

  • playwright-stealth — masks automation fingerprints
  • WebDriver spoofing — hides navigator.webdriver
  • Blink feature flags — disables AutomationControlled
  • Realistic fingerprint — Chrome 131 User-Agent, configurable locale/timezone/viewport
  • Headed mode — uses real GUI via Xvfb when available (harder to detect than headless)
  • Human-like input — variable click timing, coordinate-based clicks, realistic type delays

Using With AI Agents

Phantom is designed to be called by AI agents via subprocess. The --json flag gives structured output any agent can parse:

import subprocess, json

result = subprocess.run(
    ["phantom", "https://example.com", "--json"],
    capture_output=True, text=True
)
data = json.loads(result.stdout)
if data["ok"]:
    page_text = data["text"]

Rate Limiting

Phantom enforces a 2-second per-domain cooldown by default to prevent abuse. If you call Phantom twice against the same domain in quick succession, the second call waits automatically.

phantom https://example.com --json         # goes through immediately
phantom https://example.com --json         # waits ~2s before requesting

phantom https://other-site.com --json      # different domain, no wait

Adjust with --min-delay:

phantom https://example.com --min-delay 5   # 5s between requests (be polite)
phantom https://localhost:3000 --min-delay 0 # disable for local/owned apps

Responsible Use

Phantom is built for legitimate purposes: testing your own apps, accessing data you're authorized to retrieve, and building AI agents that browse the web respectfully.

Do:

  • Test your own web applications
  • Access sites and data you have permission to use
  • Build agents that respect robots.txt and rate limits
  • Use the default rate limiting

Don't:

  • Scrape sites that prohibit it in their ToS
  • Bypass authentication you're not authorized to use
  • Use Phantom to overwhelm or degrade services
  • Disable rate limiting against sites you don't own

The built-in rate limiter exists for a reason. If you find yourself setting --min-delay 0 against someone else's site, reconsider.

License

MIT

Metadata

Release files for phantom-browse 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for phantom-browse 0.3.1
File Size Uploaded
phantom_browse-0.3.1.tar.gz 12.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for phantom-browse 0.3.1
File Interpreter ABI Platform
phantom_browse-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 27.8 kB

Release files / phantom_browse-0.3.1.tar.gz

Download URL phantom_browse-0.3.1.tar.gz
Size 12.1 kB
Tags Source
SHA-256 checksum
How to use checksums
bcd0be33dce103b8dac1616a5647dc80216d5f5e136785c840ccfdc00f3d2133
BLAKE2b-256 checksum
How to use checksums
51c113d3b9fe2afe884852e226b747ad4097ae1aa322399e4c2fe1e0266dad56
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / phantom_browse-0.3.1-py3-none-any.whl

Download URL phantom_browse-0.3.1-py3-none-any.whl
Size 15.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b910829b918503ab64200c832e136d1fbccb4342f975ebe736b1addd459428cf
BLAKE2b-256 checksum
How to use checksums
d340aaf114c54f187f1186de61f44edfc45c7410239c49632cb712f6c444feb2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page