Let Me Log In: Giving OpenClaw a Remote Browser Handoff
The agent reaches a login screen. You take over its browser, sign in yourself, and hand control back. Making that small interaction work meant connecting the chat, the website, and the container hosting the browser.
The first version of this experience was frustrating. OpenClaw had opened a LinkedIn login tab on its server, but the link it offered pointed to 127.0.0.1. Opening that link on an iPad did not open the agent’s browser. Later, the agent explained that its browser lived on a private server and suggested finding a Control UI or Live View somewhere.
The browser existed. The login page existed. What was missing was a working route from the person in the chat to that exact browser tab.
I wanted the conversation to be simple: “Let me log in.” The Claw should create a temporary connection, provide an 8examples.com/remote-connect/<uuid> link and a six-digit code, then wait while the owner signs in.

The login has to happen in the same browser
If I sign into a website in Safari on my phone, the authenticated session belongs to Safari. It does not automatically appear in Chromium inside an OpenClaw container. The website’s cookies and other browser state live in that browser’s profile.
For this deployment, each Claw uses its managed openclaw browser profile. The owner temporarily operates that browser; we do not launch a separate browser on the owner’s behalf or copy cookies out of their personal device. OpenClaw documents its managed profile as separate from the user’s personal browser.
That continuity is what makes the handoff useful. When the owner finishes, the remote connection closes, but the existing tab, browser profile, and website login remain available to the Claw. Returning control does not log out of the destination website.
Why a Docker browser cannot just send a localhost link
In this setup, OpenClaw and its browser run on a server inside a Docker container. A loopback address is relative to the machine or network namespace using it. From inside the container, 127.0.0.1 can reach a local browser service. From an iPad, that address refers to the iPad itself.
Containers also have their own networking. With ordinary bridge networking, an internal service does not become publicly reachable merely because it is running. Docker’s networking documentation explains the distinction between container ports and published host ports.
Publishing Chrome’s debugging port would expose a much more powerful interface than a login viewer needs. Chrome’s own remote-debugging security notes describe how debugging access can be abused to extract cookies. I wanted a narrow, temporary browser connection while keeping that interface private.
A Linux display server can provide the graphical environment the browser needs; our isolated test uses Xvfb. That does not mean the owner needs a full remote Linux desktop. This feature shares browser page contents and input, which is enough for an ordinary web login.
What the owner actually does
- The Claw opens the intended login page in its existing managed browser.
- It creates a connection and sends the returned link, six-digit code, and expiry in the owner’s private chat.
- The owner opens the link and enters the connection code. This code unlocks the viewer; it is not the website’s password or MFA code.
- The owner signs into the website inside the remote view, completing supported verification steps themselves.
- They click Done — return control, then reply in the original chat. The Claw checks that the connection has ended, verifies the website is logged in, and continues the authorized task.

The distinction in the last step matters. “Control returned” means the person ended the remote session. They might have signed in successfully, cancelled, or hit another problem. The agent still has to check the website before claiming success. Clicking Done does not automatically send a message to the chat.
Keep two-factor authentication enabled
Two-factor authentication (2FA) is especially important when an account will be used by an agent. A password alone should not be the only barrier to a valuable account. 2FA adds another verification factor, such as possession of an authenticator or security key. CISA’s MFA guidance explains why that additional protection matters if a password is stolen.
The remote handoff is there to let the owner complete that verification, not to bypass it. Leave 2FA enabled. Enter a supported authenticator code into the destination website’s own login form in the remote view, or approve a legitimate sign-in through the website’s supported process. Do not paste passwords, one-time login codes, recovery codes, or authenticator setup secrets into the agent’s chat. Do not disable 2FA to make automation easier.
The six-digit connection code from the Claw is a different thing. It unlocks the temporary browser viewer. It does not satisfy the destination website’s 2FA, and sending a link and code together in one chat does not make the handoff itself two-factor authentication.
Phishing-resistant methods, including appropriately supported passkeys and security keys, provide stronger protection than codes that can be relayed to a fake site; see CISA’s phishing-resistant MFA guidance. This viewer does not forward passkeys or security keys from the owner’s device into the remote browser. If the required method cannot work here, stop and use a supported account connection or login path instead of weakening the account’s security.
After login, the Claw has access to an authenticated browser session. 2FA does not remove the need to protect its cookies, restrict what the agent is authorized to do, and revoke the website session when that access is no longer wanted. Clicking Done ends the viewer connection; it does not revoke that website session.

A public viewer, a private broker, and the existing container
The public entry point is an ordinary HTTPS page on 8examples.com. Its same-origin API route proxies a small set of requests to a broker on the private network. The website holds the broker’s service credential on the server; it is not sent to the owner’s browser or given to a tenant.

The broker runs beside Docker. It validates the tenant’s own remote-login credential and checks that the tenant is still eligible for access. It maps that identity to a fixed container name. The client cannot choose another container, supply an arbitrary CDP address, or send arbitrary debugging commands.
A trusted bridge runs inside the selected container through docker exec, communicating over standard input and output. Inside the container it attaches to the existing browser’s local Chrome DevTools Protocol endpoint. The external interface carries page images, tab information, and a restricted set of clicks, scrolls, text, and key events.
The viewer polls for frames while visible and sends input through the same website API. This version uses HTTP requests rather than a public WebSocket bridge. It fits the existing Cloudflare-to-Next.js route and does not require a public VNC port, a new domain, or exposing Chrome’s debugger.
The agent needs to know the handoff exists
A working web page was only half the change. OpenClaw also needed current instructions and an executable way to create the connection.
Each container workspace gets a remote-login skill, a small helper, and guidance in AGENTS.md. At a login step, the agent keeps the tab’s target identifier and runs:
node remote-connect/session.mjs create <targetId>
# After the owner replies in chat:
node remote-connect/session.mjs statusThe helper returns the real URL, code, and expiry. Before issuing them, the broker proves that it can reach the selected tab. The agent must not invent a plausible URL or fall back to requesting the password in chat if creation fails.
Old conversations caused another problem: they still contained obsolete VNC links and claims that the private browser could not be reached. I added a managed runtime plugin that supplies the current capability in system context. For recognized private takeover requests, it can invoke the helper directly. A delivery hook also catches specific stale login directions and replaces them with a real handoff when possible. These are targeted checks, not a guarantee that every possible model reply is correct.
While the owner has control, the instructions tell the agent to stop browser actions, screenshots, page inspection, and other agents using that browser. It ends its turn and waits for the owner. This pause is an agent instruction; the implementation does not place a process-level lock on every other tool that could access the browser.
What the security boundary does—and what it does not do
The connection is deliberately temporary. These are the implemented controls, rather than properties supplied by the URL alone:
| Control | What it limits |
|---|---|
| Random UUID + six-digit code | Knowing the link alone is insufficient. The code can be redeemed once and locks after five incorrect attempts. |
| 15-minute session lifetime | The connection has a hard expiry. Connected viewers also expire after three minutes without a viewer request; closing or suspending the page allows this timeout to take effect. |
| One active connection per Claw | A replacement ends the previous attachment. The owner or Claw can also return or revoke control. |
| Protected viewer cookie | Successful redemption sets an HttpOnly, Secure, SameSite=Strict cookie scoped to that session’s API path. Mutating viewer requests also require the expected Origin. |
| Tenant checks on viewer requests | Offboarding or a changed tenant credential invalidates an existing connection, not just new connection requests. |
| Memory-only broker sessions | Restarting the broker revokes its remote sessions. It does not erase the browser’s website login. |
Those cookie attributes restrict how the viewer credential is exposed and sent. They are part of the design alongside server-side validation; a cookie path is not a standalone security boundary.
The login viewer excludes our site analytics, session recording, and application request logging. Its responses use no-store and no-referrer. The feature does not persist browser frames or typed input in its logs or database. Only credential-free connection status goes into the Claw’s workspace.
That does not make the infrastructure blind to credentials. Input and pixels pass through the viewer, website proxy, broker, and browser. The destination page receives the login, and the authenticated browser session remains on our infrastructure. You are trusting those components and their operators. We are avoiding putting passwords in the model’s conversation, not claiming end-to-end secrecy from the remote host.
The link and code also arrive in the same private conversation. They are not two independent authentication factors, and someone who obtains both can take the handoff. The broker’s Docker access is another privileged boundary that must be protected. A container narrows the deployment’s scope; it does not make a compromised host harmless.
The bugs were in the handoff details
The first visible failure was the localhost link. After the public route worked, another failure said “Browser unavailable” when a browser or bridge temporarily stopped responding. Treating every interrupted frame as a permanently ended session made ordinary recovery painful.
The viewer now keeps its session through temporary frame or bridge failures, retries automatically for 30 seconds, and then offers Retry connection. An expired or revoked session still ends. A lost bridge can reconnect to the existing browser, and a login popup that closes can return to its surviving opener.
Next came the iPad report: scrolling worked, but tapping and typing did not reliably work. A browser viewer needs more than an image with a click handler. Input coordinates must match the dimensions of the frame actually displayed, including scrollbar gutters and zoom. Using smaller visual-viewport dimensions for a screenshot that includes scrollbars shifts the click target.
We also had to handle touch focus, physical keyboard events, paste, Unicode input, and composition. When the connection fails, queued input is discarded until a fresh frame arrives. Failed input is not blindly replayed: repeating a keystroke or a submit click could change the result.
How I checked the whole path
The useful test starts before the login and ends after the owner returns control. Our integration test boots an isolated, real OpenClaw gateway and graphical Chromium in Docker, then runs the broker and a production Next.js server. Playwright drives the viewer against a synthetic login website.
It enters test credentials, submits the form, returns control, and asks OpenClaw for a browser snapshot that proves the authenticated page is still there. It also covers incorrect and reused codes, cookie flags, cross-origin requests, temporary frame failures, bridge restart, popup switching, and a six-pixel click target with both scrollbars visible. An iPad-mode run uses WebKit, touch input, and physical keyboard events.
Separate native Telegram tests use a fake Bot API and deliberately make the model repeat obsolete private-server advice. The test checks the delivered reply contains a helper-created connection. That catches a failure a browser-only test would miss: a working viewer that the agent never offers correctly.

For rollout, I tested a canary before updating the fleet. Versioned plugin paths make the running gateway load the new code rather than retain a cached module or old manifest. Instruction-only updates can leave active browser connections alone. A broker restart has a different effect: its in-memory remote sessions end, even though the browser profiles remain.
Where this approach fits
This handoff is for browser pages, including ordinary login and verification popups. It is not a full desktop: native OS dialogs, browser chrome, file pickers, and passkeys stored on the owner’s device are outside this implementation. A website can still reject a remote session or require a verification method that this viewer cannot complete.
When a website offers an appropriate API or OAuth integration, that can be a better integration for recurring automation. The remote handoff fills the gap when the task already lives in a browser and a person needs to complete one step there.
The interaction I wanted is now possible: the Claw reaches the login page, gives me a usable connection, waits while I sign in, and resumes in that same browser. The infrastructure handles the connection; I handle my account login.
Implementation notes and related reading
The implementation is split between the managed Claw helper, broker, bridge, and runtime plugin, and the remote-connect/[id] viewer plus api/remote-connect/[...path] proxy in the 8Examples website. This post describes that deployed design, rather than a feature that every OpenClaw installation has automatically.
Comments 0
No comments yet. Start the conversation.
Leave a comment
Site author? Sign in to reply officially.
NameCommentCommenting is temporarily unavailable while CAPTCHA is being configured.