Why Hover drives your real Chrome over CDP instead of a fresh headless context
Build a tool that drives a browser and the easy path is obvious: spin up a fresh headless Chromium for every session. Clean, isolated, reproducible. It's also wrong for testing the app you're building, and the reason points straight at the path Hover took instead.
The trouble with a fresh headless context
A brand-new headless browser starts empty. No session, no login, no localStorage, no cookies. For a marketing page that's fine. For the app you're building, the one behind a login, with a populated cart, a half-filled form, a feature flag flipped on, it's a blank slate that looks nothing like what's on your screen.
So you script your way back. Log in, seed the data, toggle the flags, every session, only to reach the state your dev browser was already sitting in. The agent ends up testing a synthetic environment you rebuilt by hand, not the app you're working on.
Hover connects to a real, already-running Chrome
Hover takes the other path. It connects over the Chrome DevTools Protocol to a Chrome that's already open, and lands on the tab whose URL matches your dev-server origin. The agent drives that tab, with its real state.
So you log in once and the session persists; the agent inherits it. The agent sees the DOM, the cookies, and the localStorage you see. Popups, payment-provider redirects, and new-tab callbacks work, because it's a real browser with real tabs and not an isolated context. The agent never launches its own Chromium. It attaches to what's running and works inside it.
Not your everyday Chrome
One boundary matters here. The Chrome that Hover drives is not the browser you live in. Hover launches an isolated debug Chrome under a temporary user-data directory, with remote debugging on, pointed at your dev URL. It's a dedicated profile, reused across sessions, sitting apart from the Chrome that holds your email, your banking tabs, and fifty extensions.
Why not attach to your main browser? Because that would force you to relaunch your daily Chrome with a remote-debugging port, and it would hand the agent every tab, cookie, and extension on your main session. Hover makes the trade in the open: you log into your app once inside the debug Chrome, and from then on that profile keeps your session across commands and dev-server restarts, without ever putting your primary profile within reach.
What the widget tells you
The widget knows the page it sits in, from window.location.href. The service knows which Chrome it can reach over CDP, from /json/list. Compare the two and Hover answers a question you'd otherwise have to puzzle out: is this widget in the debug Chrome at all?
Three answers, three states. Same window means the origins match and the agent can drive this tab; you see the normal blue widget. Wrong window means a debug Chrome exists but you're not in it; one click brings the right tab forward. No debug Chrome means none is running; one click launches it on your dev URL. You never reason about ports or protocols. The widget walks you to a working state.
The principle underneath
An agent that tests your app should test the app you're building, in the state you're building it, in a real browser, the way a user would hit it. A real-but-isolated debug Chrome reached over CDP is how Hover does that without rebuilding synthetic environments and without touching the browser you live in.
Try Hover on your own app.
One command adds the widget to your dev server. Author tests with AI, ship plain Playwright.
npx @hover-dev/cli setup