Browser Connect

Connect Playwright or Puppeteer to Anakin's stealth browser

What is Browser Connect?

Browser Connect gives you a stealth browser in the cloud that you control with your own code. Connect Playwright, Puppeteer, or any CDP-compatible client to Anakin's anti-detection browser via a single WebSocket URL.

Unlike traditional scraping APIs where you submit a URL and get results back, Browser Connect gives you full browser control: navigate pages, click buttons, fill forms, take screenshots, extract data — all through your own automation scripts.


Why use Browser Connect?

  • Anti-detection built in — Stealth Firefox browser (Camoufox) with fingerprint masking, WebRTC leak prevention, and navigator.webdriver = false. No configuration needed.
  • Playwright and Puppeteer support — Connect with connect_over_cdp (Playwright) or browser.connect() (Puppeteer). No code changes beyond the connection URL.
  • Smart proxy selection — Per-domain proxy optimization via Thompson Sampling. The best proxy is automatically selected for each target site.
  • No browser infrastructure — No managing headless browsers, displays, or containers. Just connect and scrape.
  • Same API key — Uses your existing Anakin API key. No separate auth flow.

Quick Start

import asyncio
from playwright.async_api import async_playwright

API_KEY = "your_api_key"

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(
            "wss://api.anakin.io/v1/browser-connect",
            headers={"X-API-Key": API_KEY},
        )
        page = browser.contexts[0].pages[0]

        # Navigate and extract data
        await page.goto("https://books.toscrape.com", wait_until="domcontentloaded")
        print("Title:", await page.title())

        # Extract structured data
        books = await page.evaluate("""
            Array.from(document.querySelectorAll('article.product_pod')).slice(0, 5).map(el => ({
                title: el.querySelector('h3 a')?.title,
                price: el.querySelector('.price_color')?.textContent,
            }))
        """)
        print("Books:", books)

        # Take a screenshot
        await page.screenshot(path="screenshot.png")

        # Use locators
        count = await page.locator("article.product_pod").count()
        print(f"Found {count} products")

        await browser.close()

asyncio.run(main())

Supported Features

FeatureStatus
page.goto()
page.title() / page.content()
page.evaluate()
page.screenshot()
page.locator() — count, text, attributes
page.wait_for_selector()
page.wait_for_function()
page.inner_text() / page.text_content()
page.set_extra_http_headers()
page.route() — network interception
Mouse and keyboard input
Scroll / pagination
Cross-site navigation
Stealth (webdriver=false)
Session keepalive (minutes+)

Scraping Example: Extract Product Data

import asyncio
from playwright.async_api import async_playwright

async def scrape_books():
    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(
            "wss://api.anakin.io/v1/browser-connect",
            headers={"X-API-Key": "your_api_key"},
        )
        page = browser.contexts[0].pages[0]
        await page.goto("https://books.toscrape.com", wait_until="domcontentloaded")

        # Wait for products to load
        await page.wait_for_selector("article.product_pod")

        # Extract all books on the page
        books = await page.evaluate("""
            Array.from(document.querySelectorAll('article.product_pod')).map(el => ({
                title: el.querySelector('h3 a')?.title,
                price: el.querySelector('.price_color')?.textContent,
                rating: el.querySelector('.star-rating')?.className.replace('star-rating ', ''),
                inStock: !!el.querySelector('.instock'),
                link: el.querySelector('h3 a')?.href,
            }))
        """)

        print(f"Scraped {len(books)} books")
        for book in books[:3]:
            print(f"  {book['title']}{book['price']}")

        await browser.close()

asyncio.run(scrape_books())

Billing

Browser Connect sessions are billed at 1 credit per 2 minutes (rounded up). A session that lasts 3 minutes costs 2 credits.

Sessions auto-disconnect when your credits reach 0.

Limits

ParameterStarter (Free)Pro
Concurrent connections15
Max session duration15 min6 hours
Credit cost1 credit / 2 min1 credit / 2 min
Geo-targetingYes (?country=XX)Yes (?country=XX)
Max message size50 MB50 MB
AuthenticationX-API-Key headerX-API-Key header

Saved Sessions

Load a saved browser session to connect with pre-authenticated cookies and localStorage. This lets your scripts access pages that require login — without handling authentication in code.

Pass ?session_id=<uuid> or ?session_name=<name> as a query parameter:

import asyncio
from playwright.async_api import async_playwright

API_KEY = "your_api_key"
SESSION_ID = "your_session_id"  # from dashboard or GET /v1/sessions

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(
            f"wss://api.anakin.io/v1/browser-connect?session_id={SESSION_ID}",
            headers={"X-API-Key": API_KEY},
        )
        page = browser.contexts[0].pages[0]

        # Navigate to an authenticated page — cookies are pre-loaded
        await page.goto("https://amazon.com/your-orders", wait_until="domcontentloaded")
        print("Title:", await page.title())

        await browser.close()

asyncio.run(main())

You can also use the session name instead of ID:

wss://api.anakin.io/v1/browser-connect?session_name=my-amazon-login

How it works

  1. The API loads your saved session from encrypted storage
  2. The browser launches with your cookies and localStorage pre-injected
  3. If the session was created with a static IP proxy, the same proxy is reused — preventing IP mismatch issues
  4. Billing is the same (1 credit / 2 min) — no extra charge for session loading

Session query parameters

ParameterDescription
session_idUUID of the saved session
session_nameName of the saved session (must be unique per user)

If both are provided, session_id takes precedence. If neither is provided, a fresh browser is launched (default behavior).

Error responses

Session validation happens before the WebSocket connection is established, so errors are returned as standard HTTP responses:

StatusErrorMeaning
404session not foundSession ID/name doesn't exist or doesn't belong to you
422session has no stored dataSession was created but never saved — log in and save first
409session is being automatedSession is currently being used by an automation job

Saving Sessions

You can also save a session directly from Browser Connect. Pass ?save_session=<name> when connecting, and the session is automatically saved when you disconnect — no extra API calls needed.

wss://api.anakin.io/v1/browser-connect?save_session=my-amazon-login&save_url=https://amazon.com
import asyncio
from playwright.async_api import async_playwright

API_KEY = "your_api_key"

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(
            "wss://api.anakin.io/v1/browser-connect?save_session=my-amazon-login&save_url=https://amazon.com",
            headers={"X-API-Key": API_KEY},
        )
        page = browser.contexts[0].pages[0]

        # Log in programmatically
        await page.goto("https://amazon.com/signin")
        await page.fill("#email", "user@example.com")
        await page.fill("#password", "mypassword")
        await page.click("#signIn")
        await page.wait_for_url("**/your-account**")

        # Disconnect — session is auto-saved
        await browser.close()

asyncio.run(main())

Next time, load the saved session with ?session_name=my-amazon-login — see Saved Sessions above.

Save query parameters

ParameterRequiredDescription
save_sessionYesName for the saved session (must be unique per user)
save_urlNoWebsite URL associated with the session (e.g. https://amazon.com)

Save error responses

Session name is validated before the WebSocket connection starts:

StatusErrorMeaning
409session name already existsChoose a different name
503session saving not configuredServer-side encryption not set up

How saving works

  1. You connect with ?save_session=my-name
  2. The session name is validated (must be unique) before the WebSocket upgrades
  3. You automate login, navigate pages, etc.
  4. When you disconnect, the browser's cookies and localStorage are automatically extracted and encrypted
  5. The session appears in your dashboard and GET /v1/sessions
  6. If the session proxy was a static IP, it's saved too — reuse preserves the same IP

Note: Save is best-effort on disconnect. If you need guaranteed saves with visual confirmation, use the interactive browser session flow instead.


Session Recording

Record your Browser Connect session as a video. Pass ?record=true when connecting — a WebM video is automatically captured and saved when you disconnect.

wss://api.anakin.io/v1/browser-connect?record=true

You can combine recording with other features:

wss://api.anakin.io/v1/browser-connect?record=true&save_session=my-login&save_url=https://amazon.com

Retrieving recordings

After disconnecting, your recording is available via the API:

# List all recordings
curl https://api.anakin.io/v1/recordings \
  -H "X-API-Key: your_api_key"

# Get a specific recording (includes video URL)
curl https://api.anakin.io/v1/recordings/rec-123 \
  -H "X-API-Key: your_api_key"

The response includes a presigned video URL (valid for 1 hour):

{
  "id": "abc-123",
  "connId": "rec-123",
  "duration": 45,
  "fileSize": 304205,
  "status": "completed",
  "videoUrl": "https://s3.amazonaws.com/...",
  "createdAt": "2026-04-01T12:00:00Z"
}

Recordings are also available in your dashboard.

How recording works

  1. You connect with ?record=true
  2. Playwright's built-in video recording captures all page activity as WebM
  3. When you disconnect, the video is finalized, uploaded to encrypted storage, and linked to your account
  4. No extra credit cost — recording is included in the standard Browser Connect rate

Geo-Targeting

Pass ?country=XX (ISO 3166-1 alpha-2) to route the browser through a proxy in that country:

wss://api.anakin.io/v1/browser-connect?country=DE