Skip to content

Headless and headful

headless takes the literal string true on /connect and a boolean on POST /api/browser/create. It defaults to false. A browser with a window is what you get unless you ask otherwise, and it is the mode to use for any site that scores its traffic.

Headful looks like Chrome because it renders like Chrome

Section titled “Headful looks like Chrome because it renders like Chrome”

A headful session runs Chromium with a real window on a display. The page is laid out, painted and composited into that window the same way desktop Chrome does it. Everything that depends on the page actually being drawn behaves like a real machine: window geometry, frame timing, compositing, focus and visibility.

Headless Chromium skips the window and the display. The fingerprint is the same in both modes, since the user agent, fonts, canvas and WebGL come from the same profile and navigator.webdriver is false either way. What headless changes is how the browser runs, and that shows up in many places, most of them below anything a JavaScript property check would catch. A few examples:

  • No window frame. Desktop Chrome draws a frame around the page, so the outer window is larger than the viewport and a headful session reports an outerWidth larger than its innerWidth. Headless draws no frame and reports the two as equal.
  • Rendering and frame timing. Nothing is painted to a screen, so animation frames, paint timing and compositing do not follow the cadence of a displayed page.
  • Window, focus and visibility state that no desktop session produces.

A site that scores any of these treats the visit as automation before your code has run a single action. The IP, the proxy and the fingerprint are all fine, and the page still comes back as a block or a challenge. The fix is to stop sending headless=true.

Watching a headful session live is a convenience on top. It is not the reason to run one.

Terminal window
curl -G "https://browser.rayobyte.com/connect" \
--data-urlencode "os=windows" \
--data-urlencode "headless=true" \
--data-urlencode "proxy=http://USERNAME:[email protected]:8000" \
-H "x-api-key: rb_live_YOUR_KEY"

Anything other than the exact string true is read as false. headless=1 and headless=True both give you a headful browser.

Choose it when the target is not scoring the browser: your own staging site, a CI suite, an endpoint you already reach on the first try.

A headless session asked for vnc=true still returns an x-vnc-url, but there is no window for the viewer to show.

A headful browser renders into a virtual display. Add vnc=true and the response carries a URL that streams that display to you:

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"
x-vnc-url: https://sb-02.browser.rayobyte.com/vnc/vnc.html?path=ws%3Ftoken%3Dbr_5d4d8610784e2a91&autoconnect=true&resize=scale

Open it in a tab. The view is there to show you what the browser is doing, not to hand you a machine to click around in.

With the SDKs:

ws_url = client.connect_url(os="windows", vnc=True, proxy=PROXY)
print(client.last_vnc_url)
const wsUrl = await client.connectUrl({ os: 'windows', vnc: true, proxy: PROXY });
console.log(client.vncUrl);

x-vnc-url is sent only when vnc=true was requested and the browser came up with a viewer. Read it with .get() rather than indexing, or a browser that started without one raises a KeyError in the middle of an otherwise fine session.

Mode Use
Headful (default) Anything that has to look like a person. Scraping, agents, account work
Headful plus vnc=true Working out why a site is behaving differently than you expect
Headless Your own sites, CI, targets that do not challenge you

Fingerprint spoofing is identical in both modes. Headless changes how the page is rendered, and that is what sites that check for it detect.

Was this page helpful?