# shadey

Stealth browser sessions for AI agents. Pass Cloudflare, DataDome, PerimeterX, and Kasada from any IP.

## Install

```bash
pip install shadey
```

## Quick Start

```python
import asyncio
from shadey import Shadey

async def main():
    async with Shadey("sk_your_api_key") as client:
        async with await client.session() as session:
            # Navigate and extract — no CDP/Playwright needed
            await session.goto("https://example.com")
            title = await session.evaluate("document.title")
            print(title["result"])

            # Extract text from elements
            headings = await session.extract("h1", all=True)
            print(headings["data"])

            # Get full page HTML
            page = await session.content()
            print(f"{page['length']} bytes")

            # Screenshot
            img = await session.screenshot()  # base64 jpeg

asyncio.run(main())
```

## With Behavioral Actions

```python
async with Shadey("sk_your_api_key") as client:
    async with await client.session() as session:
        await session.goto("https://nowsecure.nl")

        # Human-like interactions to build trust
        await session.idle(duration_ms=3000)
        await session.scroll(400)
        await session.click(500, 300)
        await session.type_text("hello world", context="search")

        # Then extract what you need
        result = await session.extract(".result-title", all=True)
```

## With Playwright (CDP)

```python
async with Shadey("sk_your_api_key") as client:
    async with await client.session() as session:
        # Full browser control via CDP
        from playwright.async_api import async_playwright
        async with async_playwright() as p:
            browser = await p.chromium.connect_over_cdp(session.playwright_url)
            page = browser.contexts[0].pages[0]
            await page.goto("https://nowsecure.nl")
            print(await page.title())
```

## API

### `Shadey(api_key, base_url="https://api.shadey.dev")`

Create a client. Use as async context manager or call `.close()` manually.

### `client.session(stealth="full", proxy=None, profile=None)`

Create a stealth browser session. Returns a `ShadeySession`.

### REST Actions

### `session.goto(url, wait_ms=3000)`

Navigate to a URL. Waits for page load + extra `wait_ms`.

### `session.screenshot()`

Returns a base64 JPEG data URI of the current page.

### `session.extract(selector, attribute="textContent", all=False)`

Extract data from the page. Set `all=True` to get all matching elements.

### `session.evaluate(expression)`

Run JavaScript and return the result.

### `session.content()`

Get the full page HTML.

### Behavioral Actions

### `session.click(x, y, width=50)`

Move mouse and click at coordinates with Fitts' law timing and corrective submovements.

### `session.type_text(text, context="form")`

Type text with QWERTY bigram-modeled keystroke timing. Context: `"form"`, `"search"`, `"url"`.

### `session.scroll(distance)`

Scroll with momentum and inertia. Positive = down, negative = up.

### `session.dwell(context="content")`

Wait a human-realistic amount of time. Context: `"content"`, `"search"`, `"form"`.

### `session.idle(duration_ms=5000)`

Simulate idle browsing — mouse movements, scrolls, pauses driven by HMM behavioral model.

### CDP Access

### `session.playwright_url` / `session.puppeteer_url`

CDP WebSocket URL for direct browser control.

### `session.close()`

Destroy the session.

### `client.usage()`

Get plan usage stats.

### `client.health()`

Check API health.
