← Blog

BLOG

Hermes Agent-Browser Automation: Connect a Cloud Runtime

Hermes agent-browser automation explained: how to connect Hermes to a hosted Chromium runtime over CDP, what to configure, and when to move off local Chrome.

September 24, 20269 min readRemote Browser

# Hermes Agent-Browser Automation: Connect a Cloud Runtime

Hermes agent-browser automation is the practice of pointing a Hermes-style agent at a browser it does not own — a hosted Chromium session reached over CDP — instead of driving a local Chrome install. The reason to do it is boring and practical: local Chrome is a single point of failure that also happens to be your laptop. When the agent runs on a server, in CI, or across a fleet of workers, the browser has to live somewhere the agent can reach reliably. This guide covers how Hermes agent-browser automation works, what to configure, and the criteria that separate a demo from something you can leave running.

If you already know you want a hosted runtime, start with Remote Browser for AI agents for the architecture, then come back here for the Hermes-specific wiring.

What "Hermes agent-browser" actually refers to

There is no single canonical Hermes browser product. In practice the term covers a few overlapping things:

  • A Hermes agent — an LLM-driven loop that decides what to click, type, and read, then executes those decisions through a browser automation library.
  • An agent-browser layer — the CLI or SDK that translates agent intent into browser actions. The agent-browser CLI pattern (a small command surface over CDP) is the common shape.
  • A browser target — the actual Chromium process. This is the part people get wrong. It can be local, or it can be remote.

Hermes agent-browser automation is the third piece. The agent logic and the action layer stay where they are; you swap the browser target from localhost:9222 to a hosted endpoint. Everything downstream — selectors, waits, navigation — behaves the same because it is still Chromium speaking CDP.

That last point matters. A hosted runtime is not a different browser API. It is the same protocol with a different address and a different lifecycle model.

Why local Chrome breaks agent workflows

A local Chrome instance works fine until one of these happens:

Failure modeWhat it looks likeCost
Process deathChrome crashes mid-task, agent hangs on a dead socketLost run, no resume
Profile contentionTwo agents share one user-data-dir, sessions collideCorrupted state, flaky selectors
Machine sleepLaptop suspends, CDP connection dropsSilent timeout
Version driftChrome auto-updates, behavior changes between runsNon-reproducible failures
No isolationCookies and logins leak between tasksCross-contamination
Scaling ceilingYou need 20 concurrent agents, you have one machineHard stop

None of these are exotic. They are the normal failure surface of running a stateful GUI process on a machine you also use for other things.

A hosted runtime addresses the lifecycle problem specifically: sessions are created on demand, isolated by default, and torn down when the task ends. You stop treating the browser as a pet and start treating it as a resource.

How the connection works: CDP over WebSocket

Chromium exposes the Chrome DevTools Protocol over a WebSocket endpoint. Playwright, Puppeteer, and Selenium can all attach to that endpoint rather than launching their own browser. This is the mechanism behind every "remote browser" setup, including Hermes agent-browser automation.

The flow:

  1. Request a session from the runtime. You get back a WebSocket URL (a ws:// or wss:// endpoint) plus a session ID.
  2. Pass that URL to your automation library via connectOverCDP (Playwright) or connect (Puppeteer).
  3. The library speaks CDP to the remote Chromium exactly as it would to a local one.
  4. When the task finishes, you release the session. The runtime reclaims the resources.

The authoritative reference for the protocol itself is the Chrome DevTools Protocol documentation. Playwright's connectOverCDP is the client-side entry point most Hermes stacks use.

A concrete Playwright connection

This is the shape of a Hermes agent-browser connection in TypeScript. The agent loop is omitted; the point is the browser lifecycle.

import { chromium, Browser, Page } from 'playwright';

interface SessionInfo {
  cdpUrl: string;
  sessionId: string;
}

// Your runtime client returns a CDP endpoint for a fresh, isolated session.
async function createSession(): Promise<SessionInfo> {
  const res = await fetch('https://api.remote-browser.dev/sessions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.REMOTE_BROWSER_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      // Configurable browser settings: region, proxy, viewport, timeouts.
      viewport: { width: 1280, height: 800 },
      timeoutSeconds: 900,
    }),
  });
  if (!res.ok) throw new Error(`session create failed: ${res.status}`);
  return res.json();
}

async function runTask(task: (page: Page) => Promise<void>) {
  const session = await createSession();
  let browser: Browser | undefined;

  try {
    browser = await chromium.connectOverCDP(session.cdpUrl);
    // A hosted session typically exposes one default context.
    const context = browser.contexts()[0] ?? await browser.newContext();
    const page = context.pages()[0] ?? await context.newPage();

    await runTask(page);
  } finally {
    // close() detaches the client; the runtime owns teardown.
    await browser?.close();
  }
}

Two details worth noting. First, connectOverCDP does not launch anything — it attaches. Second, browser.close() on a CDP connection detaches your client; whether the remote session is destroyed depends on the runtime's session policy. Check your runtime's docs for whether you need an explicit release call.

What to configure on the browser side

The agent code is portable. The browser configuration is where hosted runtimes earn their keep, because these are the settings that are painful to manage locally.

Persistent profiles. Some tasks need to stay logged in across runs. A profile that survives session teardown means the agent does not re-authenticate every time. This is the difference between a one-shot scraper and a recurring workflow.

Proxy and network settings. Egress IP affects what sites will serve you. Residential or regional proxies are a configuration concern, not an agent concern — the agent should not know or care.

Configurable browser settings. Viewport, locale, timezone, user agent, and similar flags should be settable per session. Be precise about what you actually need; "stealth" is a marketing word, not a spec. If a runtime advertises configurable browser settings, ask exactly which properties are adjustable and whether they remain stable within a session.

Session isolation. Each task should get its own browser context at minimum, ideally its own process. Shared state between concurrent agents is a bug factory.

Live viewer. When an agent fails at step 14 of 20, a screenshot of the final state tells you nothing. A live or recorded view of the session tells you what the agent saw when it made the wrong call. This is the single highest-leverage debugging feature in a hosted runtime.

Usage controls. Timeouts, max session duration, and per-session cost visibility. You want to know what a runaway agent costs before the invoice arrives.

Choosing a runtime: criteria that matter

The market for hosted browsers is crowded. Most comparisons focus on the wrong axes. Here is what actually determines whether a runtime works for Hermes agent-browser automation.

CriterionWhy it mattersWhat to verify
CDP compatibilityYour agent library must attach without modificationconnectOverCDP works; no proprietary action API required
Session isolationConcurrent agents must not share stateSeparate contexts or processes per session
Profile persistenceRecurring tasks need durable loginsProfiles survive teardown; opt-in, not forced
Live debuggingFailures are visual, not textualLive viewer or session recording available
Proxy supportEgress IP determines site behaviorRegional/residential options, per-session config
Pricing modelAgent workloads are bursty and long-tailedMetered by browser-time, not seats; see /pricing
Framework supportYou may not use Playwright foreverPlaywright, Puppeteer, Selenium all supported

The pricing row deserves emphasis. Agent tasks have a long tail — most finish in seconds, some run for many minutes. A seat-based or per-request model punishes exactly the workloads agents produce. Metered browser-time is the model that fits. Current rates and included usage are on the pricing page; do not plan capacity against numbers you read in a blog post.

When to stay local, and when to move

Hosted is not automatically correct. The honest trade-off:

Stay local if you are prototyping, running a single agent interactively, and can tolerate the browser dying when you close the lid. The setup cost of a hosted runtime is not worth it for a script you run twice.

Move to hosted when any of these are true:

  • The agent runs unattended, on a schedule, or in CI.
  • You need more than one concurrent session.
  • Tasks require persistent logins you do not want on your machine.
  • You need to debug failures after the fact.
  • You are paying an engineer to babysit Chrome.

The transition itself is small. You change where the CDP URL comes from and add a session create/release step. The agent logic does not move. If you want to see the runtime side without committing, Remote Browser online covers running real Chromium without local setup.

Common failure modes and how to read them

Most Hermes agent-browser problems are connection or lifecycle problems, not agent problems. The symptoms:

`connectOverCDP` times out. The endpoint is wrong, the session already expired, or your network blocks the WebSocket. Verify the URL is current — session URLs are usually short-lived.

Agent hangs mid-task. The CDP socket dropped. Add a heartbeat or a per-action timeout so the agent fails fast instead of waiting on a dead connection.

Selectors work locally, fail remotely. Usually a viewport or user-agent difference. Pin both in session config.

Session leaks. You are creating sessions without releasing them. Track session IDs and release in a finally block, as in the code above.

Login state missing. The profile was not persisted, or you are hitting a different session than the one that logged in. Confirm profile reuse is enabled and that you are requesting the same profile ID.

For a broader look at driving hosted Chromium from code and agents, remote control browser covers the control-plane patterns.

A minimal production checklist

Before you call a Hermes agent-browser setup production-ready:

  • [ ] Sessions are created per task, not shared across tasks.
  • [ ] Every session is released in a finally block or equivalent.
  • [ ] Per-action timeouts are set; the agent cannot hang indefinitely.
  • [ ] Profile persistence is opt-in and scoped to tasks that need it.
  • [ ] A live viewer or recording is available for post-mortem debugging.
  • [ ] Proxy and region settings are explicit, not inherited from defaults.
  • [ ] Cost per session is observable; see /pricing for the metering model.
  • [ ] The agent code has no hardcoded localhost browser paths.

That last item is the one people forget. If your agent constructs a local browser path anywhere, you have not actually moved to a hosted runtime — you have added one next to a local one.

Where Remote Browser fits

Remote Browser provides hosted Chromium sessions with CDP access, Playwright/Puppeteer/Selenium compatibility, persistent profiles, configurable browser settings, session isolation, a live viewer, and usage controls. It is a runtime, not an agent framework — it does not decide what to click. That is your Hermes agent's job, and it stays portable because the connection is standard CDP.

The practical test: if your agent can point at a different CDP URL and keep working, you have the right abstraction. If it cannot, the coupling is in your code, not the runtime.

Start with the documentation to get a session URL, then wire it into your existing Hermes loop. The agent logic does not change. Only the browser's address does.