Headless browser: why an attached tab ignores clicks
What a headless browser is, why a tab a driver only attaches to runs at 0 frames per second and ignores input in both modes, and what a site can tell from headless.

Davide Valli · Founder, Scalebrowser
Published Oct 28, 2026 · 6 min read
Short answer

An agent clicks a button, the driver answers that the click was dispatched, and the page does not move. The usual suspect is headless mode, and the usual fix is to switch it off and watch a window. That fix often changes nothing, because the cause sits in which tab is in front, not in whether there is a window at all.
What is a headless browser?
A headless browser is a browser that runs without a visible user interface, driven by a program instead of a person. It loads pages, runs their scripts and renders them the way a normal browser does, and it hands the result to its driver instead of a screen. That makes it the default for tests, scrapers and agents on machines where nobody is watching. Chrome has had two implementations of it:
| Mode | Window | Code |
|---|---|---|
| Headed | created and shown | Chrome |
| New headless, since Chrome 112 | created, not shown | the same code as headed |
| Old headless, since Chrome 59 | none | a separate implementation |
The new mode closed most of the gap between the two. What is left is the difference a page can still read, and a second difference that has nothing to do with the mode.
Which headless mode does your tool start?
Your tool starts the new headless mode if it is Puppeteer or Chrome with --headless, and the old one if it is Playwright with its defaults. The old implementation still exists: since Chrome 132 it ships only as a standalone binary, chrome-headless-shell, and Playwright downloads that binary for its headless runs.
| Tool | Starts by default when headless | How to get the other mode |
|---|---|---|
| Chrome from the command line | new headless, with --headless | the separate chrome-headless-shell binary |
| Puppeteer | new headless, headless: true | headless: 'shell' |
| Playwright | the headless shell | channel: 'chromium' for new headless |
Chrome's headless documentation describes the new mode as one in which Chrome "creates, but doesn't display, any platform windows", and adds: "All other functions, existing and future, are available with no limitations." Playwright, according to its browser documentation, ships "a separate chromium headless shell for headless mode" and calls the new mode "the real Chrome browser, and is thus more authentic, reliable, and offers more features". A test suite on the defaults of these two tools therefore runs two different browser implementations.
A headless browser still renders the page; it skips the display, not the drawing. In our tab measurement the front tab of a headless browser drew 59.8 animation frames per second, the same rate as a headed one, and Chrome's command line reference captures that rendering directly: --screenshot saves the page as an image and --print-to-pdf as a PDF.
Why does an attached tab stop rendering?
An attached tab stops rendering because attaching to a tab over the Chrome DevTools Protocol does not bring it to the front, and Chrome treats every tab that is not in front as a background tab. A background tab reports visibilityState hidden, draws no animation frames and runs its timers about once per second. We measured it on 10 August 2026 with two tabs of the same origin, reading only what each page saw, in both modes and in two builds of Chromium 150.
| How the driver takes the tab | Headless, our engine | Headless, plain Chromium | Headed, our engine | Headed, plain Chromium |
|---|---|---|---|---|
| attached | hidden, 0 fps | hidden, 0 fps | hidden, 0 fps | hidden, 0 fps |
| attached and activated | visible, 59.8 fps | visible, 59.8 fps | visible, 60.4 fps | visible, 59.8 fps |
| attached and brought to front | visible, 60.4 fps | visible, 59.8 fps | visible, 59.8 fps | visible, 59.8 fps |
Every column answers the same way, so this is Chromium's rule and not a defect of one build or one mode. It matches what browsers document. MDN notes that requestAnimationFrame() "calls are paused in most browsers when running in background tabs", and its timer documentation describes Chrome checking a hidden page's timers "once per second", then "once per minute" after 5 minutes hidden, among other conditions. Our hidden tabs ran their timers 0.6 to 1.4 times a second against 10 to 10.7 in front.
The input is the part that costs runs. Input dispatched into a hidden tab arrives nowhere, while the protocol answers as if it had landed, so a driver that does not check which tab is in front reports clicks that never happened. The fix is to activate the bound tab before every gesture, which also produces the ordinary blur, visibilitychange and focus sequence of a person switching tabs, instead of injecting those events.
A visible window does not settle the question either. On 8 September 2026 a headed window on a Windows desktop where nobody was sitting reported visibilityState hidden while it held the focus, because Chrome's occlusion detection considered it unseen, and it swallowed every input the driver sent. The headed arm of that run had to be dropped.
Can a site tell headless from headed?
A site can tell a stock headless Chrome from a headed one, and whether it can tell a given browser depends on everything that browser exposes, not on the mode alone. Kernel's bot detection documentation says browsers started without a visible window "expose subtle differences (rendering, GPU, fonts)", and its advice is to "avoid headless mode". In our runs of Reddit's own page checks on 8 September 2026, a stock headless Chrome driven over CDP was flagged by how it had been launched before it clicked anything, in 2 of 2 runs, while a Scalebrowser profile started headless raised no marker on the same page in its 1 run.
The mode is one input among several. A site reads the TLS connection, the JavaScript fingerprint, the way the browser is driven and the timing of the input, and a headless browser can fail any of them for reasons unrelated to its missing window: a server without a graphics card renders in software, and a driver that never activates its tab runs a page at 0 frames per second in either mode. How the reputation of the exit address weighs on a run is covered in IP reputation for browser automation.
The screen is one of those inputs. Chrome's page on headless screen configuration says headless mode uses "a fully configurable virtual headless screen which is independent of physical displays attached to the system", set with the --screen-info switch. A page that measures the screen of a headless browser therefore measures what the launcher configured, not the machine's display. A Scalebrowser profile takes its screen size and available area from the machine's own desktop at every start, as the coherence documentation describes.
The article on the detection layers of a browser takes the four in order, and the direct CDP documentation shows how a profile is started headless or with a window. How Claude Code works with a real browser, and what each step costs in tokens, is covered in Claude Code with a real browser.
Run it on your own machine
Seven days to try it with your own agents on your own sites. Starting the trial needs a card.

Written by
Davide Valli
Founder, Scalebrowser
Builds Scalebrowser, the browser layer for AI agents that runs on your own machine. Measures every change a web page could observe against a real browser before it ships, and writes up the ones that turned out wrong.
All articles by Davide Valli