# Agent Browser Google Chrome Linux

> Use this skill whenever you need to automate or control Google Chrome on Linux using the user's existing authenticated session on any site — particularly sites that block automated or headless sign-in (MFA, CAPTCHA, OAuth, bot detection). Trigger any time the user asks you to "use Chrome", "open the browser", "automate a website", "control the browser", "use agent-browser", or wants to do something on a site they're already logged into. Also trigger when the user mentions CDP, remote debugging, or connecting to a running Chrome instance on Linux. This skill is essential whenever agent-browser needs an authenticated session — don't skip it, since missing the profile-copy step will drop you on a sign-in page you can't get past.

- Skill: `iamriajul/agent-browser-google-chrome-linux` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add iamriajul/agent-browser-google-chrome-linux`
- Raw SKILL.md: https://api.skillmd.com/api/skills/iamriajul/agent-browser-google-chrome-linux/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: iamriajul (https://skillmd.com/u/iamriajul)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/iamriajul/agent-browser-google-chrome-linux

---


# Controlling a User's Authenticated Chrome via agent-browser (Linux)

## agent-browser

Install once if not present:

```bash
npm i -g agent-browser
```

Do **not** run `agent-browser install` — that downloads a testing Chromium with no user session, which defeats the purpose of this skill.

Before running any agent-browser commands, load the actual workflow content from the CLI:

```bash
agent-browser skills get core             # workflows, common patterns, troubleshooting
agent-browser skills get core --full      # include full command reference and templates
```

The CLI serves skill content that always matches the installed version, so instructions never go stale.

## The Core Constraint

Chrome refuses remote debugging on the default user-data-dir (`~/.config/google-chrome`) for security. You'll see this error in `/tmp/chrome.log`:

```
DevTools remote debugging requires a non-default data directory. Specify this using --user-data-dir.
```

**The fix:** copy the user's profile to a non-default dir, kill all Chrome, launch from the copy with the debug port, connect agent-browser via CDP.

## Step 0: Find the Right DISPLAY

Everyone's Linux setup is different. Before launching Chrome, find the X display where the user's desktop session is running:

```bash
# Option A: check what the user's shell already has
echo $DISPLAY

# Option B: scan running processes for an X display
ps aux | grep -oP 'DISPLAY=\S+' | sort -u

# Option C: list /tmp/.X11-unix sockets (each one is a display)
ls /tmp/.X11-unix/
# X0 → :0, X1 → :1, etc.

# Option D: look at who's logged into the X session
who | grep '(:[0-9]'
```

Common values are `:0`, `:1`, or `:10`. Use whatever you find — substitute it for `DISPLAY=:1` in the recipe below. If you're in a Kasm/VNC environment, `:1` is typical, but verify first.

If `echo $DISPLAY` returns something, that's the right one. If it's empty, you're likely in an SSH session without X forwarding — look at the X11-unix sockets or check with the user.

## The Recipe (run in order, every time)

Before going through the full setup, check if Chrome is already running with the debug port — if so, you can skip straight to connecting:

```bash
# Quick check: is port 9222 already listening?
curl -s -m 2 http://127.0.0.1:9222/json/version | head -2
```

If that returns a `{"Browser": "Chrome/...` response, Chrome is already up with remote debugging enabled. Run the verification one-liner from the Verification section below — if you land on the target site (not a sign-in page), you're done, skip the rest of the recipe.

If the port is not listening, or you land on a sign-in page, proceed with the full recipe:

```bash
# 1. Kill ALL Chrome processes (any leftover holds the SingletonLock)
pkill -9 -f 'google-chrome\|/opt/google/chrome/chrome'
sleep 3
pgrep -af chrome | grep -v 'crashpad\|chrome-devtools\|grep'  # confirm empty

# 2. Verify the user's session is fresh in their profile
ls -la ~/.config/google-chrome/Default/Cookies   # check mtime is recent

# 3. Copy profile to a non-default location, strip the lock files
rm -rf /tmp/chrome-debug-profile
cp -a ~/.config/google-chrome /tmp/chrome-debug-profile
rm -f /tmp/chrome-debug-profile/Singleton{Lock,Cookie,Socket}

# 4. Launch Chrome with debug port on the display the user can see
#    Replace :1 with the DISPLAY value you found in Step 0
DISPLAY=:1 nohup google-chrome \
  --remote-debugging-port=9222 \
  --user-data-dir=/tmp/chrome-debug-profile \
  --no-sandbox --no-first-run --no-default-browser-check \
  'https://target-url-to-load-immediately' \
  >/tmp/chrome.log 2>&1 &
disown

# 5. Confirm port is listening (3-7s after launch)
sleep 6
curl -s -m 3 http://127.0.0.1:9222/json/version | head -2
# Expect: {"Browser": "Chrome/...

# 6. Connect agent-browser to the running Chrome
agent-browser --session <name> connect 9222
agent-browser --session <name> get url   # sanity check
```

From here, every `agent-browser --session <name> ...` command drives the same Chrome window the user can see.

## Why Each Flag Matters

| Flag | Why |
|---|---|
| `DISPLAY=:1` | Targets the X display where the user's session is running — find the right value with Step 0 |
| `--remote-debugging-port=9222` | The CDP endpoint agent-browser connects to |
| `--user-data-dir=/tmp/chrome-debug-profile` | Required by Chrome's "non-default data dir" rule |
| `--no-sandbox` | Required in many container/coder envs (no SUID sandbox available) |
| `--no-first-run --no-default-browser-check` | Skip welcome dialogs that block initial render |
| `disown` | So the bg job survives if the parent shell exits |

## Gotchas

**1. `/tmp` gets wiped between sessions.**
Coder/sandbox envs sometimes clean `/tmp`. If `/tmp/chrome-debug-profile` has shrunk dramatically since last use (e.g., 168M → 59M), the session is corrupt — re-copy from `~/.config/google-chrome`.

**2. User must be signed in somewhere first.**
Re-copying from `~/.config/google-chrome` only works if the user has a valid session there. If cookies have expired or been invalidated, you'll land on a sign-in page you can't get past — ask the user to re-auth in their normal Chrome first, then re-copy.

**3. Multiple Chrome instances ≠ multiple debug ports.**
If the user runs another `google-chrome` (without flags), it joins the existing instance. Only the *first* one with `--remote-debugging-port` binds the port. Always `pkill` first.

**4. Old singleton files block startup.**
After `cp -a`, always `rm -f Singleton{Lock,Cookie,Socket}` from the copy or Chrome refuses to launch.

**5. Don't try to log in via the debug Chrome.**
Sites that block automated sign-in (MFA prompts, CAPTCHA, OAuth flows, headless browser detection) will block you here too. The recipe sidesteps this entirely by piggybacking on a session the user already established in their normal Chrome.

**6. agent-browser can disappear.**
`agent-browser` is npm-installed globally, and `nvm`/tmp cleanups can wipe it. Reinstall with `npm i -g agent-browser` (~5s), then `connect 9222` again — Chrome's session survives independently.

**7. Never run `agent-browser install`.**
`agent-browser install` downloads a separate testing Chromium binary with no user profile or cookies. Always use the system `google-chrome` binary.

**8. Initial page blank/loading.**
Chrome takes 3-7s after launch before CDP responds. Always `sleep 6` then `curl /json/version` before connecting.

## Verification

After launch, confirm the whole chain works:

```bash
agent-browser --session <name> connect 9222 && \
  agent-browser --session <name> get url
```

- **Real URL on the target site** → you're in.
- **A sign-in or auth page** → copied session is stale or expired. Ask the user to re-auth in their normal Chrome, then re-copy.

## When NOT to Use This

If the target site doesn't require authentication, skip the profile copy and launch a fresh empty profile:

```bash
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/fresh-chrome --no-sandbox &
```

The copy-the-user's-profile dance is *only* needed for sites where you can't automate login — MFA, CAPTCHA, OAuth flows, or headless browser detection at the sign-in page.

