Introduction
Nimble’s Browserless API lets you drive our cloud browsers directly from your own automation via standard Chromium WebSocket/CDP endpoints. Use your existing Puppeteer or Playwright code, connect over a pre‑signed WS/CDP URL from your Nimble dashboard, and get full fidelity browsing with JavaScript rendering, network capture, and Chrome DevTools Protocol control. See the related docs for Browser API behavior, rendering controls, and driver selection.
What you get
-
Native Puppeteer and Playwright connectivity via WS/CDP (no code rewrites)
-
Real browser execution with JS, cookies, storage, and anti‑bot evasion handled by Nimble’s stack
-
Network event capture and full CDP access for performance, tracing, or advanced automation
-
Optional rendering, geotargeting, and resource controls when you create sessions/jobs via the Web API (driver, render_type, blocked_domains, etc.)
Supported connection patterns
| Client | How to connect | Notes |
|---|---|---|
| Puppeteer (Node.js) | puppeteer.connect({ browserWSEndpoint }) | Use the pre‑signed wss:// endpoint from your dashboard/session. |
| Playwright (Node.js) | chromium.connectOverCDP(cdpUrl) | Use a CDP URL (ws:// or http://) exposed for your session. |
| Playwright (Python) | chromium.connect_over_cdp(cdp_url) | Same as Node; works with sync or async variants. |
Tip: Create or retrieve a pre‑signed WS/CDP URL from your Nimble dashboard or job/session API, then inject it at runtime via an environment variable. See rendering/driver controls and blocked_domains in the API docs for deterministic runs.
Quick start: Puppeteer (Node.js)
npm i puppeteer
export NIMBLE_WS_URL="wss://<your-pre-signed-endpoint>"
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.connect({
browserWSEndpoint: process.env. NIMBLE_WS_URL,
ignoreHTTPSErrors: true,
defaultViewport: { width: 1280, height: 800 }
});
const page = await browser.newPage();
// Basic navigation with robust wait condition
await page.goto('https://example.com', { waitUntil: 'networkidle2', timeout: 60_000 });
// Network capture (responses)
page.on('requestfinished', async (req) => {
try {
const res = await req.response();
const url = req.url();
const status = res.status();
const ctype = (res.headers()['content-type'] || '').toLowerCase();
if (ctype.includes('application/json')) {
const body = await res.text();
console.log('[JSON]', status, url, body.slice(0, 200));
} else {
console.log('[RES]', status, url);
}
} catch (e) {
console.warn('Network parse error:', e);
}
});
// CDP session for low-level control
const cdp = await page.target().createCDPSession();
await cdp.send('Network.enable');
await cdp.send('Page.enable');
// Example: get layout metrics via CDP
const metrics = await cdp.send('Page.getLayoutMetrics');
console.log('Layout metrics:', metrics?.contentSize);
await browser.disconnect();
})();
Quick start: Playwright (Node.js)
npm i playwright
export NIMBLE_CDP_URL="wss://<your-pre-signed-cdp-endpoint>"
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.connectOverCDP(process.env. NIMBLE_CDP_URL);
const context = browser.contexts().length ? browser.contexts()[0]: await browser.newContext();
const page = await context.newPage();
page.on('response', async (res) => {
const url = res.url();
const status = res.status();
console.log('[RES]', status, url);
});
await page.goto('https://example.com', { waitUntil: 'networkidle' });
const session = await context.newCDPSession(page);
await session.send('Network.enable');
await session.send('Performance.enable');
const timing = await session.send('Performance.getMetrics');
console.log('Perf metrics count:', timing?.metrics?.length);
await browser.close();
})();
Quick start: Playwright (Python)
pip install playwright
playwright install chromium
export NIMBLE_CDP_URL="wss://<your-pre-signed-cdp-endpoint>"
import os
from playwright.sync_api import sync_playwright
cdp_url = os.environ["NIMBLE_CDP_URL"]
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
context = browser.contexts[0] if browser.contexts else browser.new_context()
page = context.new_page()
def on_response(res):
print('[RES]', res.status, res.url)
page.on('response', on_response)
page.goto('https://example.com', wait_until='networkidle')
# CDP session
client = context.new_cdp_session(page)
client.send('Network.enable')
client.send('Runtime.enable')
eval_result = client.send('Runtime.evaluate', params={"expression": "document.title"})
print('Title via CDP:', eval_result.get('result', {}).get('value'))
browser.close()
Rendering, drivers, and resource controls
-
Control rendering and waiting strategies (load/domready/idle) when you create jobs via the Web API, then attach over WS/CDP to that session. This gives deterministic page states for your tests and scrapes.
-
Lock a specific Browserless Driver for cost/performance predictability (vx6/vx8/vx10 and pro variants).
-
Reduce noise and speed up runs by blocking third‑party domains (ads/analytics) at render time.
-
Maintain multi‑step state by capturing and reusing cookies between steps when using the Web API for session orchestration.
Network capture patterns
-
High‑level: use page.on('response') / page.on('request') (Puppeteer/Playwright) to record URLs, status, headers, and filter JSON/XHR.
-
Low‑level: enable CDP Network domain and subscribe to events (responseReceived, loadingFinished) for HAR‑like traces, timing, and bodies when available.
-
Best practice: keep PII out of logs and mask tokens. See Nimble’s compliance guidance.
Geotargeting and session setup
If you need country/state/city targeting, set these when you create the underlying session (via Web API) so the attached WS/CDP browser inherits the locale, IP, and fingerprint. Combine with rendering and driver parameters for reproducible runs.
Troubleshooting
-
Connection fails immediately: verify the pre‑signed WS/CDP URL is valid and not expired; ensure your egress can reach wss:// over 443.
-
Handshake succeeds but newPage() hangs: confirm the session wasn’t created with resource blocking that breaks your target (e.g., over‑aggressive blocked_domains).
-
Intermittent timeouts on dynamic SPAs: set an appropriate render_type (e.g., idle2) in the job/session, then wait for network idle in code.
-
High bandwidth/slow runs: block noisy third‑party assets and avoid downloading videos/fonts.
-
Multi‑step flows lose context: persist cookies between steps or reuse the same session.
Security and compliance
Nimble is built with compliance‑by‑design (GDPR/CCPA/SOC 2), ethical IP sourcing, audit trails, and zero‑trust controls. Keep automation within Acceptable Use, collect only public data, and mask sensitive values in logs.