Skip to content

Connecting

GET /connect creates a browser and answers with its CDP WebSocket URL as plain text. That is the whole call.

Terminal window
curl -i -G "https://browser.rayobyte.com/connect" \
--data-urlencode "os=windows" \
--data-urlencode "vnc=true" \
--data-urlencode "proxy=http://USERNAME:[email protected]:8000" \
-H "x-api-key: rb_live_YOUR_KEY"
HTTP/2 200
x-session-id: br_3f8a1c9d2e4b5a60
x-vnc-url: https://sb-02.browser.rayobyte.com/vnc/vnc.html?path=ws%3Ftoken%3Dbr_5d4d8610784e2a91&autoconnect=true&resize=scale
content-type: text/plain; charset=utf-8
wss://sb-02.browser.rayobyte.com/cdp/br_5d4d8610784e2a91

The body is the URL and nothing else: no JSON wrapper, no guaranteed trailing newline. Trim it before you use it.

The br_ id at the end of the CDP URL is a second id for the same session. Close and status accept either id. Reconnect takes only the x-session-id value and answers 404 Session not found to the CDP URL’s id.

cloud.rayobrowse.com is an alias for browser.rayobyte.com and answers identically, so older code keeps working without a change.

Each sample closes the session when it is done. Playwright’s browser.close() and Puppeteer’s disconnect() only detach the client, so the close call is what stops the browser.

import httpx
from playwright.sync_api import sync_playwright
API = "https://browser.rayobyte.com"
KEY = "rb_live_YOUR_KEY"
resp = httpx.get(
f"{API}/connect",
params={
"os": "windows",
"proxy": "http://USERNAME:[email protected]:8000",
},
headers={"x-api-key": KEY},
timeout=120,
)
if resp.status_code != 200:
raise SystemExit(f"{resp.status_code}: {resp.text}")
cdp_url = resp.text.strip()
session_id = resp.headers["x-session-id"]
try:
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
context = browser.contexts[0]
page = context.pages[0] if context.pages else context.new_page()
page.goto("https://quotes.toscrape.com/")
print(page.title())
finally:
httpx.post(
f"{API}/api/browser/close",
json={"browserId": session_id},
headers={"x-api-key": KEY},
timeout=30,
)

proxy is required. Everything else has a default.

ParameterDefaultExampleDescription
proxy (required)proxy=http://user:[email protected]:8000Route the browser's traffic through this proxy. Mandatory on every launch. Accepted schemes are http, https, socks5 and socks5h, and the port must be written out.
oswindowsos=windowsFingerprint OS: windows, android, linux, macos.
headlessfalseheadless=trueRun without a window. The literal string true enables it; any other value is false. Sites can detect it: see Headless and headful.
vncfalsevnc=trueReturn an x-vnc-url header for the live view.
maxLifetime7200maxLifetime=3600Session lifetime in seconds, clamped into 120 to 86400. 0 counts as omitted.
sessionIdnonesessionId=br_3f8a1c9d2e4b5a60Reconnect to a running session, using the x-session-id value. Every other parameter is ignored and no browser is created.
tokennonetoken=rb_live_...Your API key as a query parameter, in place of the x-api-key header.
browser_version_mincurrentbrowser_version_min=NLowest Chromium major version the profile may claim. Defaults to the version the browser runs. See Version matching.
browser_version_maxcurrentbrowser_version_max=NHighest Chromium major version the profile may claim. Defaults to the version the browser runs.
browser_languageautobrowser_language=en-USAccept-Language value.
ui_languageautoui_language=en-USBrowser UI locale.
screen_width_minautoscreen_width_min=1280Lowest screen width the profile may have.
screen_height_minautoscreen_height_min=720Lowest screen height the profile may have.
force_visibilityfalseforce_visibility=trueKeep a background or unfocused tab reporting itself as visible and focused. The literal string true only.
metadatanonemetadata=%7B%22job%22%3A%22crawl-42%22%7DURL-encoded JSON object stored on the session. A value that does not parse is dropped without an error.

Build the query string with a URL library, or curl -G --data-urlencode as the examples here do. A proxy password containing @, :, /, #, %, & or a space has to be percent-encoded, and a plain curl "...?proxy=..." will not do it for you. See Proxy support for the exact rules and what each malformed form returns.

The proxy travels in the query string, so client errors that print the request URL print its password too. httpx’s raise_for_status() is one of them. The examples above print the status and body instead. To keep credentials out of URLs altogether, send the same fields as a JSON body to POST /api/browser/create.

Header Description
x-session-id The session id, br_ plus 16 hex characters. Keep it: reconnecting needs it
x-vnc-url The live view, sent only when vnc=true and the browser came up with one
x-ratelimit-limit Your concurrent browser limit, 5 by default. Despite the name, not the per-minute rate limit
x-ratelimit-remaining Concurrent browsers still free after this one
X-Error-Code On a 400, 422 or 503, the machine-readable code: PROXY_REQUIRED, PROXY_INVALID, PROXY_UNREACHABLE or CAPACITY

Pass sessionId and no browser is created. You get the CDP URL of the session you already have:

Terminal window
curl "https://browser.rayobyte.com/connect?sessionId=br_3f8a1c9d2e4b5a60&vnc=true" \
-H "x-api-key: rb_live_YOUR_KEY"

Every other parameter on a reconnect is ignored. Sending os=android alongside sessionId does not change the fingerprint of a running browser, and nothing warns you that it was dropped.

A reconnect is not subject to the concurrency or rate limits, so it works when all 5 browsers are running.

A session that has ended answers 410 Session is CLOSED (or DEAD, or EXPIRED). An id that never existed, an id that belongs to another account, or the id from a CDP URL answers 404 Session not found. Both are final; retrying returns the same thing.

Every session survives a CDP disconnect, whichever way it was created. Closing it, its lifetime running out, or the browser dying are the three things that end one. See Session management.

  1. Checks your key, your concurrency, your rate and your remaining browser hours.
  2. Checks the proxy’s form. It does not dial the proxy.
  3. Picks a backend with a free seat and starts Chromium on it. The browser dials the proxy at this point, and a proxy it cannot get through answers 422 PROXY_UNREACHABLE.
  4. Rewrites the browser’s internal address into its public sb-NN.browser.rayobyte.com form and returns that.
  5. Steps out. Your CDP traffic goes to the backend directly and the gateway sees none of it.

Was this page helpful?