Integrations / Automation libraries / Raw CDP
The DevTools Protocol, with nothing in between.
Every library above speaks CDP underneath. When you want only a few commands, skip the library: start a Browz profile, take its page target from the DevTools endpoint and send commands over a WebSocket.
export BROWZ_TOKEN="$(cat ~/.browz/api-token)"
curl -s -X POST http://127.0.0.1:50333/api/v1/browser/start -H "Authorization: Bearer $BROWZ_TOKEN" -H "Content-Type: application/json" \
-d '{"id":"<profile id>"}'Setup
Set it up.
Install Browz and open it
Start a profile
The answer has
debugPort,cdpEndpoint(http://) andwsEndpoint(the browser’s ws:// URL).Terminalexport BROWZ_TOKEN="$(cat ~/.browz/api-token)" curl -s -X POST http://127.0.0.1:50333/api/v1/browser/start -H "Authorization: Bearer $BROWZ_TOKEN" -H "Content-Type: application/json" \ -d '{"id":"<profile id>"}'Send commands to the page
Node 22 or later has WebSocket and fetch built in. The browser-level socket speaks Target.*; for one page, its own socket from /json/list is simpler.
cdp.mjsconst cdp = process.argv[2]; // the cdpEndpoint, http://127.0.0.1:<port> const target = (await (await fetch(`${cdp}/json/list`)).json()).find((t) => t.type === 'page'); const ws = new WebSocket(target.webSocketDebuggerUrl); await new Promise((ok) => ws.addEventListener('open', ok, { once: true })); let next = 0; const send = (method, params = {}) => new Promise((ok, fail) => { const id = ++next; const onMessage = ({ data }) => { const msg = JSON.parse(data); if (msg.id !== id) return; ws.removeEventListener('message', onMessage); msg.error ? fail(new Error(msg.error.message)) : ok(msg.result); }; ws.addEventListener('message', onMessage); ws.send(JSON.stringify({ id, method, params })); }); await send('Page.navigate', { url: 'https://example.com' }); await new Promise((r) => setTimeout(r, 2000)); // or wait for Page.loadEventFired const { result } = await send('Runtime.evaluate', { expression: 'document.title', returnByValue: true }); console.log(result.value); ws.close();
Methods from Chrome DevTools Protocol.
Example
Run it, then stop the profile.
Pass the cdpEndpoint from the start call, then stop the profile through Browz so it saves cleanly.
node cdp.mjs http://127.0.0.1:<debugPort>
curl -s -X POST http://127.0.0.1:50333/api/v1/browser/stop -H "Authorization: Bearer $BROWZ_TOKEN" -H "Content-Type: application/json" \
-d '{"id":"<profile id>"}'It prints Example Domain.
Good to know
Notes and tips.
- The script does not send
Runtime.enable:Runtime.evaluateworks without it, and a page can notice side effects of an enabled Runtime domain. - The DevTools endpoint listens on 127.0.0.1 only, like the local API.
- Attach to the browser Browz started; never let the library launch its own. A library-launched browser is a stock one with none of the profile’s fingerprint, proxy or cookies.
- A person completes sign-ins, 2FA codes and CAPTCHAs in the profile’s window; your script can wait for the page that follows. Browz never solves or bypasses CAPTCHAs.
- Automate only where each site’s terms allow it. Our acceptable use policy applies to scripts the same as to people.
- The local API, CDP and the SDKs are on every plan, Free included (5 profiles), and are not metered.
FAQ
Raw CDP and Browz.
Which port is the DevTools endpoint on?
A new one each start: it is debugPort in the start answer. cdpEndpoint is http://127.0.0.1:debugPort.
Is CDP access limited to some plans?
No. CDP, the local API and the SDKs are on every plan, Free included.
Can I attach Chrome DevTools itself?
Yes. Open http://127.0.0.1:debugPort/json/list and use a page’s devtoolsFrontendUrl, or add localhost:debugPort under chrome://inspect in another Chromium browser.
Get started
Download Browz. Every task, its own browser.
curl -fsSL https://gobrowz.com/agents/install.sh | sh