608 lines
17 KiB
Markdown
608 lines
17 KiB
Markdown
# Browser API (Scraping Browser) Reference
|
|
|
|
## Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Authentication](#authentication)
|
|
- [Connection Strings](#connection-strings)
|
|
- [Supported Frameworks](#supported-frameworks)
|
|
- [Session Rules](#session-rules)
|
|
- [Quick Start Examples](#quick-start-examples)
|
|
- [Custom CDP Functions](#custom-cdp-functions)
|
|
- [Geolocation Targeting](#geolocation-targeting)
|
|
- [Bandwidth Optimization](#bandwidth-optimization)
|
|
- [CAPTCHA Handling](#captcha-handling)
|
|
- [Debugging](#debugging)
|
|
- [Premium Domains](#premium-domains)
|
|
- [Error Codes](#error-codes)
|
|
- [Billing Model](#billing-model)
|
|
- [Best Practices](#best-practices)
|
|
- [Anti-Patterns](#anti-patterns)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Bright Data Browser API (also called Scraping Browser) is a managed cloud browser service. It handles proxy management, fingerprinting, CAPTCHA solving, and bot detection bypass automatically. Use it when you need full browser automation: clicking, scrolling, form filling, JavaScript execution, or working with SPAs.
|
|
|
|
**When to use Browser API vs other APIs:**
|
|
|
|
| Need | Use |
|
|
|------|-----|
|
|
| Simple HTTP scraping, no interaction | Web Unlocker |
|
|
| Google/Bing search results | SERP API |
|
|
| Structured data from known platforms | Web Scraper API |
|
|
| Click, scroll, fill forms, run JS | **Browser API** |
|
|
| Intercept XHR/fetch calls from a page | **Browser API** |
|
|
| Handle complex anti-bot that requires browser | **Browser API** |
|
|
| Puppeteer/Playwright/Selenium automation | **Browser API** |
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
Get credentials from your Browser API zone's **Overview tab** in the Control Panel.
|
|
|
|
- **Username:** `brd-customer-{CUSTOMER_ID}-zone-{ZONE_NAME}`
|
|
- **Password:** Your zone password
|
|
|
|
```bash
|
|
export BROWSER_AUTH="brd-customer-CUSTOMER_ID-zone-ZONE_NAME:PASSWORD"
|
|
```
|
|
|
|
---
|
|
|
|
## Connection Strings
|
|
|
|
| Framework | Connection Type | Endpoint |
|
|
|-----------|----------------|----------|
|
|
| Playwright | WebSocket | `wss://${AUTH}@brd.superproxy.io:9222` |
|
|
| Puppeteer | WebSocket | `wss://${AUTH}@brd.superproxy.io:9222` |
|
|
| Selenium | HTTPS | `https://${AUTH}@brd.superproxy.io:9515` |
|
|
|
|
Replace `${AUTH}` with `username:password`.
|
|
|
|
**Critical:** Wrong port = 407 error. Playwright/Puppeteer = port `9222`. Selenium = port `9515`.
|
|
|
|
---
|
|
|
|
## Supported Frameworks
|
|
|
|
- **Node.js:** Puppeteer, Playwright, Selenium WebDriver
|
|
- **Python:** Playwright, Selenium
|
|
- **C# (.NET):** PuppeteerSharp, Playwright, Selenium
|
|
- **Other languages:** Any language with CDP or WebDriver support (Ruby, Go, Java, etc.)
|
|
|
|
---
|
|
|
|
## Session Rules
|
|
|
|
- **One initial navigation per session.** After `page.goto(url)`, you can interact (click, scroll, evaluate) within the same page, but cannot navigate to a different URL in the same session. Start a new session for a new target.
|
|
- **Idle timeout:** Sessions inactive for **5+ minutes** automatically close.
|
|
- **Maximum duration:** Sessions cannot exceed **30 minutes**.
|
|
- **Password entry:** Disabled by default to protect non-public data. Contact Bright Data to enable.
|
|
|
|
---
|
|
|
|
## Quick Start Examples
|
|
|
|
### Playwright (Node.js)
|
|
|
|
```javascript
|
|
const { chromium } = require("playwright-core");
|
|
|
|
const AUTH = process.env.BROWSER_AUTH || "brd-customer-CUSTOMER_ID-zone-ZONE_NAME:PASSWORD";
|
|
const TARGET_URL = "https://example.com";
|
|
|
|
(async () => {
|
|
const browser = await chromium.connectOverCDP(
|
|
`wss://${AUTH}@brd.superproxy.io:9222`
|
|
);
|
|
const page = await browser.newPage();
|
|
|
|
// Set navigation timeout to 2 minutes (recommended for complex unlocking)
|
|
page.setDefaultNavigationTimeout(120000);
|
|
|
|
await page.goto(TARGET_URL, { waitUntil: "domcontentloaded" });
|
|
const html = await page.content();
|
|
console.log(html);
|
|
|
|
await browser.close();
|
|
})();
|
|
```
|
|
|
|
### Playwright (Python)
|
|
|
|
```python
|
|
import asyncio
|
|
from playwright.async_api import async_playwright
|
|
|
|
AUTH = "brd-customer-CUSTOMER_ID-zone-ZONE_NAME:PASSWORD"
|
|
TARGET_URL = "https://example.com"
|
|
|
|
async def main():
|
|
async with async_playwright() as p:
|
|
browser = await p.chromium.connect_over_cdp(
|
|
f"wss://{AUTH}@brd.superproxy.io:9222"
|
|
)
|
|
page = await browser.new_page()
|
|
page.set_default_navigation_timeout(120000)
|
|
|
|
await page.goto(TARGET_URL, wait_until="domcontentloaded")
|
|
html = await page.content()
|
|
print(html)
|
|
|
|
await browser.close()
|
|
|
|
asyncio.run(main())
|
|
```
|
|
|
|
### Puppeteer (Node.js)
|
|
|
|
```javascript
|
|
const puppeteer = require("puppeteer-core");
|
|
|
|
const AUTH = process.env.BROWSER_AUTH || "brd-customer-CUSTOMER_ID-zone-ZONE_NAME:PASSWORD";
|
|
|
|
(async () => {
|
|
const browser = await puppeteer.connect({
|
|
browserWSEndpoint: `wss://${AUTH}@brd.superproxy.io:9222`
|
|
});
|
|
const page = await browser.newPage();
|
|
page.setDefaultNavigationTimeout(120000);
|
|
|
|
await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
|
|
const html = await page.content();
|
|
console.log(html);
|
|
|
|
await browser.close();
|
|
})();
|
|
```
|
|
|
|
### Selenium (Python)
|
|
|
|
```python
|
|
from selenium import webdriver
|
|
from selenium.webdriver.chrome.options import Options
|
|
|
|
AUTH = "brd-customer-CUSTOMER_ID-zone-ZONE_NAME:PASSWORD"
|
|
|
|
options = Options()
|
|
options.add_argument("--ignore-certificate-errors")
|
|
|
|
driver = webdriver.Remote(
|
|
command_executor=f"https://{AUTH}@brd.superproxy.io:9515",
|
|
options=options
|
|
)
|
|
driver.get("https://example.com")
|
|
print(driver.page_source)
|
|
driver.quit()
|
|
```
|
|
|
|
---
|
|
|
|
## Custom CDP Functions
|
|
|
|
Bright Data extends standard CDP with specialized commands. Use `page.evaluate` or `client.send` to invoke them.
|
|
|
|
### CAPTCHA Handling
|
|
|
|
#### `Captcha.setAutoSolve`
|
|
Control automatic CAPTCHA solving.
|
|
|
|
```javascript
|
|
// Disable auto-solve (use manual control instead)
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Captcha.setAutoSolve", { autoSolve: false });
|
|
```
|
|
|
|
#### `Captcha.solve`
|
|
Manually trigger CAPTCHA solving and wait for completion.
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
const result = await client.send("Captcha.solve", { timeout: 30000 });
|
|
console.log(result.status); // "solved" | "not_detected" | "timeout"
|
|
```
|
|
|
|
```python
|
|
# Python equivalent
|
|
client = await page.context.new_cdp_session(page)
|
|
result = await client.send("Captcha.solve", {"timeout": 30000})
|
|
print(result["status"])
|
|
```
|
|
|
|
### Geolocation
|
|
|
|
#### `Proxy.setLocation`
|
|
Set precise proxy location by coordinates. **Must be called before navigating to the site.**
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Proxy.setLocation", {
|
|
latitude: 37.7749,
|
|
longitude: -122.4194,
|
|
distance: 10, // Search radius in km
|
|
strict: true // true = only peers within distance; false = expand if none found
|
|
});
|
|
await page.goto("https://example.com");
|
|
```
|
|
|
|
```python
|
|
client = await page.context.new_cdp_session(page)
|
|
await client.send("Proxy.setLocation", {
|
|
"latitude": 37.7749,
|
|
"longitude": -122.4194,
|
|
"distance": 10,
|
|
"strict": True
|
|
})
|
|
await page.goto("https://example.com")
|
|
```
|
|
|
|
### Session Management
|
|
|
|
#### `Proxy.useSession`
|
|
Maintain consistent proxy peer across multiple browsing sessions (same IP continuity).
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Proxy.useSession", { sessionId: "my-session-123" });
|
|
```
|
|
|
|
### Device Emulation
|
|
|
|
#### `Emulation.getSupportedDevices`
|
|
Get list of available device profiles.
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
const { devices } = await client.send("Emulation.getSupportedDevices");
|
|
console.log(devices); // ["iPhone 14", "Samsung Galaxy S21", ...]
|
|
```
|
|
|
|
#### `Emulation.setDevice`
|
|
Apply a specific device profile (user agent, screen size, touch).
|
|
|
|
```javascript
|
|
await client.send("Emulation.setDevice", {
|
|
deviceName: "iPhone 14"
|
|
});
|
|
// Optional: landscape orientation
|
|
await client.send("Emulation.setDevice", {
|
|
deviceName: "iPhone 14",
|
|
landscape: true
|
|
});
|
|
```
|
|
|
|
### Ad Blocking
|
|
|
|
#### `Unblocker.enableAdBlock` / `Unblocker.disableAdBlock`
|
|
Block/unblock ads to reduce bandwidth on content-heavy sites.
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Unblocker.enableAdBlock");
|
|
// ... scrape page ...
|
|
await client.send("Unblocker.disableAdBlock"); // if needed later
|
|
```
|
|
|
|
### Input Acceleration
|
|
|
|
#### `Input.type`
|
|
Faster text input than standard keyboard simulation. Useful for bulk form-filling.
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Input.type", {
|
|
text: "search query here",
|
|
selector: "#search-input"
|
|
});
|
|
```
|
|
|
|
### File Downloads
|
|
|
|
#### `Download.*`
|
|
Control file downloads with content-type filtering.
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Download.setDownloadBehavior", {
|
|
behavior: "allow",
|
|
downloadPath: "/tmp/downloads"
|
|
});
|
|
// Retrieve file as base64
|
|
const { data } = await client.send("Download.getDownloadedFile", {
|
|
guid: "download-guid-here"
|
|
});
|
|
```
|
|
|
|
### Security / Client Certificates
|
|
|
|
#### `Browser.addCertificate`
|
|
Install a client SSL/TLS certificate for authenticated domain access. Certificate is automatically removed when the session ends.
|
|
|
|
```javascript
|
|
await client.send("Browser.addCertificate", {
|
|
host: "example.com",
|
|
certificate: "base64-encoded-cert",
|
|
privateKey: "base64-encoded-key"
|
|
});
|
|
```
|
|
|
|
### Debugging
|
|
|
|
#### `Page.inspect`
|
|
Get a Chrome DevTools debugger URL to connect and inspect the live session.
|
|
|
|
```javascript
|
|
const { url } = await client.send("Page.inspect");
|
|
console.log(`DevTools: ${url}`);
|
|
// Open in Chrome or use programmatically
|
|
```
|
|
|
|
---
|
|
|
|
## Geolocation Targeting
|
|
|
|
### Country-Level (via credentials)
|
|
Append `-country-XX` to your username (2-letter ISO code):
|
|
|
|
```javascript
|
|
const AUTH = "brd-customer-ID-zone-NAME-country-us:PASSWORD";
|
|
const browser = await chromium.connectOverCDP(`wss://${AUTH}@brd.superproxy.io:9222`);
|
|
```
|
|
|
|
**EU targeting** — automatically routes through 29+ European countries:
|
|
```javascript
|
|
const AUTH = "brd-customer-ID-zone-NAME-country-eu:PASSWORD";
|
|
```
|
|
|
|
### Precise Location (via CDP)
|
|
Use `Proxy.setLocation` for city/neighborhood-level targeting. **Call before `page.goto()`**:
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Proxy.setLocation", {
|
|
latitude: 51.5074, // London
|
|
longitude: -0.1278,
|
|
distance: 5, // 5km radius
|
|
strict: false // expand search if no peers found nearby
|
|
});
|
|
await page.goto("https://example.com");
|
|
```
|
|
|
|
---
|
|
|
|
## Bandwidth Optimization
|
|
|
|
Browser sessions are billed by traffic. These techniques reduce costs:
|
|
|
|
### Block Unnecessary Resources
|
|
|
|
```javascript
|
|
// Puppeteer
|
|
await page.setRequestInterception(true);
|
|
page.on("request", (req) => {
|
|
const blocked = ["image", "stylesheet", "font", "media"];
|
|
if (blocked.includes(req.resourceType())) {
|
|
req.abort();
|
|
} else {
|
|
req.continue();
|
|
}
|
|
});
|
|
```
|
|
|
|
```python
|
|
# Playwright
|
|
async def block_resources(route, request):
|
|
blocked = ["image", "stylesheet", "font", "media"]
|
|
if request.resource_type in blocked:
|
|
await route.abort()
|
|
else:
|
|
await route.continue_()
|
|
|
|
await page.route("**/*", block_resources)
|
|
```
|
|
|
|
### Block Specific URLs (CDP)
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Network.setBlockedURLs", {
|
|
urls: [
|
|
"*google-analytics*",
|
|
"*facebook.com/tr*",
|
|
"*.doubleclick.net*"
|
|
]
|
|
});
|
|
```
|
|
|
|
### Enable Ad Blocker
|
|
|
|
```javascript
|
|
await client.send("Unblocker.enableAdBlock");
|
|
```
|
|
|
|
### Browser Caching
|
|
Browser API automatically caches resources across multiple navigations to the same domain within a session. No extra configuration needed.
|
|
|
|
---
|
|
|
|
## CAPTCHA Handling
|
|
|
|
### Automatic (Default)
|
|
CAPTCHA solving is enabled by default. No code needed — the browser solves CAPTCHAs transparently.
|
|
|
|
### Detect and Wait for CAPTCHA
|
|
|
|
```javascript
|
|
// Navigate and wait for CAPTCHA to be solved automatically
|
|
const client = await page.target().createCDPSession();
|
|
await page.goto("https://example.com");
|
|
|
|
// If CAPTCHA appears, explicitly wait for it
|
|
const captchaResult = await client.send("Captcha.solve", { timeout: 60000 });
|
|
if (captchaResult.status === "solved") {
|
|
console.log("CAPTCHA solved");
|
|
}
|
|
```
|
|
|
|
### Disable Auto-Solve
|
|
|
|
```javascript
|
|
const client = await page.target().createCDPSession();
|
|
await client.send("Captcha.setAutoSolve", { autoSolve: false });
|
|
// Now you control when/if to solve CAPTCHAs
|
|
```
|
|
|
|
---
|
|
|
|
## Debugging
|
|
|
|
### Via Control Panel
|
|
Navigate to your Browser API zone → Overview tab → Click "Chrome Dev Tools Debugger".
|
|
|
|
### Via CDP Command
|
|
|
|
```javascript
|
|
const { url } = await client.send("Page.inspect");
|
|
// Opens Chrome DevTools for the live session
|
|
```
|
|
|
|
### Programmatic Inspection (Playwright)
|
|
Playwright provides a `slowMo` and debug URL option. Use `Page.inspect` to get the debug URL and connect with Chrome.
|
|
|
|
---
|
|
|
|
## Premium Domains
|
|
|
|
Certain websites classified as "premium" require more Browser API resources:
|
|
|
|
- Enable during zone creation: toggle "Premium Domains" ON
|
|
- Only traffic to premium-classified domains incurs the higher rate
|
|
- The list of premium domains updates regularly based on Bright Data's algorithms
|
|
- Check current premium domain list in your zone settings
|
|
|
|
---
|
|
|
|
## Error Codes
|
|
|
|
| Code | Issue | Solution |
|
|
|------|-------|----------|
|
|
| `407` | Wrong port | Playwright/Puppeteer = port `9222`, Selenium = port `9515` |
|
|
| `403` | Authentication failure | Verify username format and password; confirm you're using a Browser API zone (not proxy zone) |
|
|
| `503` | Service unavailable (scaling) | Reconnect after 1 minute |
|
|
|
|
---
|
|
|
|
## Billing Model
|
|
|
|
| Factor | Detail |
|
|
|--------|--------|
|
|
| Pricing unit | Traffic-based only (bandwidth consumed) |
|
|
| Time/instance fees | None |
|
|
| Session idle timeout | 5 minutes — sessions close automatically |
|
|
| Session max duration | 30 minutes |
|
|
| Resource blocking | Reduces bandwidth = reduces cost |
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
### 1. Always set navigation timeout to 2 minutes
|
|
Complex anti-bot procedures take time. Default timeouts (30s) are too short.
|
|
|
|
```javascript
|
|
page.setDefaultNavigationTimeout(120000); // 2 minutes
|
|
```
|
|
|
|
### 2. Call `Proxy.setLocation` before navigation
|
|
Location selection must happen before `page.goto()` to ensure the correct proxy is selected.
|
|
|
|
```javascript
|
|
// CORRECT: Set location first
|
|
await client.send("Proxy.setLocation", { latitude: 37.7749, longitude: -122.4194, distance: 10 });
|
|
await page.goto("https://example.com");
|
|
|
|
// WRONG: Location set after navigation has no effect on proxy selection
|
|
await page.goto("https://example.com");
|
|
await client.send("Proxy.setLocation", { ... }); // too late
|
|
```
|
|
|
|
### 3. Block unnecessary resources to cut bandwidth costs
|
|
Images, stylesheets, and fonts are often not needed for data extraction. Block them.
|
|
|
|
```javascript
|
|
await page.route("**/*.{png,jpg,jpeg,gif,svg,css,woff,woff2}", route => route.abort());
|
|
```
|
|
|
|
### 4. Use `waitUntil: "domcontentloaded"` over `networkidle`
|
|
`networkidle` waits for all network activity to stop, which is slow and often unnecessary. `domcontentloaded` is faster and sufficient for most pages.
|
|
|
|
```javascript
|
|
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
```
|
|
|
|
### 5. Start a fresh session for each new target URL
|
|
Since only one initial navigation per session is allowed, create a new browser connection for each independent scraping task.
|
|
|
|
```javascript
|
|
async function scrapeUrl(url) {
|
|
const browser = await chromium.connectOverCDP(`wss://${AUTH}@brd.superproxy.io:9222`);
|
|
try {
|
|
const page = await browser.newPage();
|
|
page.setDefaultNavigationTimeout(120000);
|
|
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
return await page.content();
|
|
} finally {
|
|
await browser.close();
|
|
}
|
|
}
|
|
```
|
|
|
|
### 6. Use `Proxy.useSession` for IP continuity across sessions
|
|
When you need the same IP for multiple requests (e.g., login → scrape → logout flow across sessions):
|
|
|
|
```javascript
|
|
await client.send("Proxy.useSession", { sessionId: "user-session-abc123" });
|
|
```
|
|
|
|
### 7. Use `Unblocker.enableAdBlock` for content-heavy sites
|
|
Ad networks add significant bandwidth. Blocking ads reduces costs on news sites, blogs, and similar pages.
|
|
|
|
### 8. Use `Emulation.setDevice` for mobile-specific pages
|
|
Some sites serve different content to mobile users. Set the device profile instead of manually setting user agent.
|
|
|
|
```javascript
|
|
await client.send("Emulation.setDevice", { deviceName: "iPhone 14" });
|
|
await page.goto("https://example.com/mobile");
|
|
```
|
|
|
|
### 9. Monitor sessions via `Page.inspect` during development
|
|
During development, use `Page.inspect` to get a live DevTools URL to debug what the browser actually sees.
|
|
|
|
### 10. Use `Input.type` for bulk form filling
|
|
`Input.type` is faster than simulating individual keystrokes — important when filling many fields at scale.
|
|
|
|
---
|
|
|
|
## Anti-Patterns
|
|
|
|
**DO NOT use proxy networks with Playwright/Puppeteer/Selenium.**
|
|
Browser automation libraries should connect to Browser API, not route through a proxy. The Browser API endpoint (`wss://...`) replaces proxy configuration entirely.
|
|
|
|
**DO NOT reuse sessions for different target URLs.**
|
|
One session = one `page.goto()`. After that, interact only with the loaded page. For new URLs, create new sessions.
|
|
|
|
**DO NOT set navigation timeout below 60 seconds.**
|
|
Bright Data's unlocking procedures can take time. Anything below 60 seconds risks premature timeouts on difficult sites. Recommended: 120 seconds.
|
|
|
|
**DO NOT enable custom headers unless required.**
|
|
Custom headers/cookies shift billing from success-only to 100% of all requests.
|
|
|
|
**DO NOT rely on `networkidle` for SPA pages.**
|
|
Single-page applications may never reach true `networkidle` state. Use specific element waiters instead:
|
|
```javascript
|
|
await page.waitForSelector(".product-data", { timeout: 30000 });
|
|
```
|