BLOG
Hermes Remote Browser Not Working: Fixes and Setup
Hermes remote browser not working? Diagnose connection, CDP, and session errors, then wire Hermes agents to a hosted Chromium runtime reliably.
# Hermes Remote Browser Not Working: Fixes and Setup
If your Hermes remote browser is not working, the failure is almost always one of four things: the browser endpoint is unreachable, the CDP handshake is rejected, the session died mid-task, or the agent is pointed at a local Chrome that no longer exists. This guide walks through each failure mode, shows how to confirm which one you are hitting, and explains how to wire Hermes to a hosted Chromium runtime so the connection survives restarts, retries, and scale.
The short version: Hermes needs a stable CDP endpoint, not a browser binary on the same machine. When you run Hermes against a remote browser, you separate the agent process from the browser process. That separation is what makes failures diagnosable — and fixable.
Why Hermes remote browser connections fail
Hermes is an agent framework that drives a browser through a control protocol, typically Chrome DevTools Protocol (CDP) or a Playwright/Puppeteer connection layer. When you point it at a remote browser, several things must line up:
- The endpoint URL must be reachable from wherever the Hermes process runs.
- The browser must expose a CDP websocket that accepts the connection.
- The session must stay alive for the duration of the task.
- The agent's browser tool must be configured to use the remote endpoint, not a bundled local browser.
Most "not working" reports trace back to a mismatch in one of these four. Let's take them in order.
Symptom 1: Connection refused or timeout
If Hermes throws ECONNREFUSED, ETIMEDOUT, or a websocket handshake error, the endpoint is not reachable. Common causes:
- The browser session was never started, or it already expired.
- The endpoint host is only reachable from inside a VPC, and your Hermes worker is outside it.
- A firewall or egress rule blocks the CDP port.
- You copied a
ws://URL from a dashboard that has since rotated.
Fix: verify reachability before blaming Hermes. From the same host that runs the agent:
curl -sS -o /dev/null -w "%{http_code}\n" https://<your-endpoint>/json/versionA healthy hosted Chromium returns 200 with a JSON body containing webSocketDebuggerUrl. If that call fails, Hermes will fail too — the problem is network or session lifecycle, not the agent.
Symptom 2: CDP handshake rejected
You can reach the endpoint, but the connection drops immediately. This usually means:
- The session token or API key is missing, expired, or scoped to a different project.
- You are connecting to the HTTP port instead of the websocket URL.
- The browser was launched without remote debugging enabled.
Playwright's connectOverCDP is strict about this. If you pass an HTTP endpoint where a websocket is expected, you get an opaque error rather than a clear message. Always use the webSocketDebuggerUrl value, not the base host.
Symptom 3: Session dies mid-task
The connection works, the agent starts, then the browser disappears halfway through. Causes:
- The session hit an idle timeout because the agent paused on a slow model call.
- The worker running Hermes was recycled (common on serverless or spot instances).
- The browser process crashed on a heavy page.
This is the failure mode that local Chrome hides and remote browsers expose. It is also the one that matters most in production, because a task that dies at step 14 of 20 wastes the whole run.
Symptom 4: Hermes is still using local Chrome
Sometimes nothing is broken — Hermes simply never switched to the remote browser. The agent's browser tool defaults to launching a local Chromium. If that binary is missing (common in slim containers), you get a launch error that looks like a remote-browser problem but is not.
Check the agent's browser configuration. If it references a local executable path or chromium.launch(), it is not using your remote endpoint.
Diagnosing the failure in order
Work through this checklist before changing any code:
- Confirm the session exists. Open the live viewer for the session and check it is running.
- Confirm reachability. Run the
curlcheck above from the agent host. - Confirm the URL type. Use the websocket URL, not the HTTP base.
- Confirm auth. Verify the token is present and not expired.
- Confirm the agent config. Make sure Hermes is told to connect, not launch.
- Confirm session lifetime. Check idle timeout against your longest model call.
If all six pass and it still fails, the issue is usually in how the agent handles reconnects. That is a code problem, and the next section covers it.
Wiring Hermes to a hosted Chromium runtime
The reliable pattern is: create a session via the runtime API, get its CDP websocket URL, and hand that URL to Hermes. The agent never launches a browser; it connects to one that already exists.
Here is a TypeScript example using Playwright's CDP connection, which is the same path Hermes uses under the hood:
import { chromium } from "playwright";
type Session = {
id: string;
cdpUrl: string; // webSocketDebuggerUrl from the runtime
};
async function runHermesTask(session: Session) {
const browser = await chromium.connectOverCDP(session.cdpUrl, {
timeout: 30_000,
});
// Reuse the existing context so cookies and storage persist
const context = browser.contexts()[0] ?? (await browser.newContext());
const page = context.pages()[0] ?? (await context.newPage());
try {
await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
// ... hand `page` to your Hermes browser tool here
} finally {
// Disconnect without killing the remote browser
await browser.close();
}
}Two details matter here:
- `connectOverCDP`, not `launch`. This is the difference between using a remote browser and starting a local one.
- `browser.close()` disconnects; it does not terminate the remote session. That is what you want if the session should outlive the agent run. If you want the session gone, close it through the runtime API instead.
For the full connection surface — profiles, proxies, and session controls — see the documentation.
Local Chrome vs hosted Chromium for Hermes
The table below summarizes why the local setup breaks and what changes when the browser is hosted.
| Concern | Local Chrome | Hosted Chromium runtime |
|---|---|---|
| Browser binary | Must exist on every worker | Managed by the runtime |
| CDP endpoint | localhost, dies with the process | Stable URL, survives worker restarts |
| Session lifetime | Tied to the agent process | Independent, configurable idle timeout |
| Scaling | One browser per worker, memory-bound | Sessions created on demand |
| Debugging | Attach locally, hard in containers | Live viewer + CDP from anywhere |
| Profile persistence | Manual user-data-dir | Persistent profiles per session |
| Proxy / network settings | Per-machine config | Configurable per session |
| Failure visibility | Opaque crashes | Session state and logs |
The trade-off is real: a hosted runtime adds a network hop and a dependency. For a one-off script on your laptop, local Chrome is fine. For anything that runs on a schedule, in a container, or across more than one worker, the hosted model removes an entire class of failures.
Production criteria for a Hermes browser runtime
If you are choosing a runtime rather than debugging one, evaluate against these criteria:
- CDP compatibility. It must expose a standard CDP websocket so Playwright, Puppeteer, and Selenium can all connect. Avoid runtimes that only offer a proprietary SDK.
- Session isolation. Each agent task should get its own browser context so cookies and storage do not leak between runs.
- Persistent profiles. For workflows that require login state, profiles must survive across sessions.
- Live viewer. You need to see what the agent sees when a task fails at step 14.
- Configurable browser settings. Proxy, locale, timezone, and user-agent should be settable per session.
- Usage controls. You should be able to cap session duration and concurrency to control cost. Current limits and rates are on the pricing page.
- Reconnect semantics. The runtime should let you reconnect to a live session after a worker restart.
If a runtime cannot answer these, it will not survive production traffic.
Common Hermes-specific pitfalls
Beyond the four failure modes, a few Hermes-specific issues show up repeatedly:
The agent closes the browser after every step. Some browser tools call browser.close() at the end of each action. Against a remote session, that tears down the connection and forces a reconnect. Configure the tool to keep the connection open for the task duration.
Model latency exceeds the idle timeout. A slow LLM call can leave the browser idle long enough to be reaped. Either raise the idle timeout or send a lightweight keepalive (a page.title() call) between steps.
Concurrent tasks share one session. If two Hermes tasks connect to the same CDP endpoint, they will fight over tabs and navigation state. Create one session per task. This is the single most common cause of "it works alone but breaks under load."
Retries reuse a dead session. When a task fails and retries, it must create a fresh session or verify the old one is still alive. Reusing a stale cdpUrl produces exactly the connection-refused error from Symptom 1.
The agent assumes a visible browser. Headless and headed sessions behave differently for some sites. If a workflow depends on rendering, confirm the session mode matches.
When to move off local Chrome entirely
The decision is straightforward. Move to a hosted runtime when any of these are true:
- Your agent runs in a container, serverless function, or CI job.
- You need more than a handful of concurrent sessions.
- Tasks must survive worker restarts.
- You need to debug failures after the fact.
- You are managing proxies or profiles across machines.
Stay local when you are prototyping a single workflow on a machine you control and do not care about persistence.
For a broader look at how the runtime layer fits into agent architecture, see Remote Browser for AI Agents. If you want to understand the connection model without installing anything, Remote Browser Online covers the browser-as-a-service path.
A minimal recovery procedure
When Hermes remote browser is not working and you need it back fast, run this sequence:
- Kill the current session and create a new one.
- Copy the new
webSocketDebuggerUrl. - Verify it with
curlfrom the agent host. - Update the agent's browser config to the new URL.
- Run a single-step task (navigate + read title) before the full workflow.
- If the single step passes, the full task will too — if it fails, the problem is in the agent's step logic, not the connection.
This isolates connection problems from task problems, which is the fastest way to stop guessing.
Summary
A Hermes remote browser that is not working is usually a connection, auth, lifetime, or configuration problem — not a Hermes bug. The fix is to stop launching browsers from inside the agent and start connecting to a hosted Chromium session over CDP. That gives you a stable endpoint, independent session lifetime, a live viewer for debugging, and the ability to scale past one worker.
Start by confirming reachability with a single curl against /json/version. If that passes, the rest is configuration. If it fails, you have found your problem — and it is not in your agent code.
For connection details, session controls, and the full API surface, see the documentation. For current session limits and rates, check pricing.