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) orbrowser.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())const { chromium } = require('playwright');
const API_KEY = 'your_api_key';
(async () => {
const browser = await chromium.connectOverCDP(
'wss://api.anakin.io/v1/browser-connect',
{ headers: { 'X-API-Key': API_KEY } }
);
const page = browser.contexts()[0].pages()[0];
await page.goto('https://books.toscrape.com', { waitUntil: 'domcontentloaded' });
console.log('Title:', await page.title());
const 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,
}))
);
console.log('Books:', books);
await page.screenshot({ path: 'screenshot.png' });
await browser.close();
})();const puppeteer = require('puppeteer-core');
const API_KEY = 'your_api_key';
(async () => {
const browser = await puppeteer.connect({
browserWSEndpoint: 'wss://api.anakin.io/v1/browser-connect',
headers: { 'X-API-Key': API_KEY },
});
const page = (await browser.pages())[0] || await browser.newPage();
await page.goto('https://books.toscrape.com', {
waitUntil: 'domcontentloaded',
timeout: 30000,
});
console.log('Title:', await page.title());
console.log('HTML:', (await page.content()).length, 'chars');
await page.screenshot({ path: 'screenshot.png' });
await browser.disconnect();
})();Supported Features
| Feature | Status |
|---|---|
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
| Parameter | Starter (Free) | Pro |
|---|---|---|
| Concurrent connections | 1 | 5 |
| Max session duration | 15 min | 6 hours |
| Credit cost | 1 credit / 2 min | 1 credit / 2 min |
| Geo-targeting | Yes (?country=XX) | Yes (?country=XX) |
| Max message size | 50 MB | 50 MB |
| Authentication | X-API-Key header | X-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())const { chromium } = require('playwright');
const API_KEY = 'your_api_key';
const SESSION_ID = 'your_session_id';
(async () => {
const browser = await chromium.connectOverCDP(
`wss://api.anakin.io/v1/browser-connect?session_id=${SESSION_ID}`,
{ headers: { 'X-API-Key': API_KEY } }
);
const page = browser.contexts()[0].pages()[0];
await page.goto('https://amazon.com/your-orders', { waitUntil: 'domcontentloaded' });
console.log('Title:', await page.title());
await browser.close();
})();const puppeteer = require('puppeteer-core');
const API_KEY = 'your_api_key';
const SESSION_ID = 'your_session_id';
(async () => {
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://api.anakin.io/v1/browser-connect?session_id=${SESSION_ID}`,
headers: { 'X-API-Key': API_KEY },
});
const page = (await browser.pages())[0] || await browser.newPage();
await page.goto('https://amazon.com/your-orders', {
waitUntil: 'domcontentloaded',
timeout: 30000,
});
console.log('Title:', await page.title());
await browser.disconnect();
})();You can also use the session name instead of ID:
wss://api.anakin.io/v1/browser-connect?session_name=my-amazon-loginHow it works
- The API loads your saved session from encrypted storage
- The browser launches with your cookies and localStorage pre-injected
- If the session was created with a static IP proxy, the same proxy is reused — preventing IP mismatch issues
- Billing is the same (1 credit / 2 min) — no extra charge for session loading
Session query parameters
| Parameter | Description |
|---|---|
session_id | UUID of the saved session |
session_name | Name 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:
| Status | Error | Meaning |
|---|---|---|
| 404 | session not found | Session ID/name doesn't exist or doesn't belong to you |
| 422 | session has no stored data | Session was created but never saved — log in and save first |
| 409 | session is being automated | Session 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.comimport 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())const { chromium } = require('playwright');
const API_KEY = 'your_api_key';
(async () => {
const browser = await chromium.connectOverCDP(
'wss://api.anakin.io/v1/browser-connect?save_session=my-amazon-login&save_url=https://amazon.com',
{ headers: { 'X-API-Key': API_KEY } }
);
const 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');
// Disconnect — session is auto-saved
await browser.close();
})();Next time, load the saved session with ?session_name=my-amazon-login — see Saved Sessions above.
Save query parameters
| Parameter | Required | Description |
|---|---|---|
save_session | Yes | Name for the saved session (must be unique per user) |
save_url | No | Website URL associated with the session (e.g. https://amazon.com) |
Save error responses
Session name is validated before the WebSocket connection starts:
| Status | Error | Meaning |
|---|---|---|
| 409 | session name already exists | Choose a different name |
| 503 | session saving not configured | Server-side encryption not set up |
How saving works
- You connect with
?save_session=my-name - The session name is validated (must be unique) before the WebSocket upgrades
- You automate login, navigate pages, etc.
- When you disconnect, the browser's cookies and localStorage are automatically extracted and encrypted
- The session appears in your dashboard and
GET /v1/sessions - 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=trueYou can combine recording with other features:
wss://api.anakin.io/v1/browser-connect?record=true&save_session=my-login&save_url=https://amazon.comRetrieving 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
- You connect with
?record=true - Playwright's built-in video recording captures all page activity as WebM
- When you disconnect, the video is finalized, uploaded to encrypted storage, and linked to your account
- 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