Attach Chrome
Use this guide when:
- Chrome already exists outside PinchTab
- you want the PinchTab server to register that browser as an instance
- you already have a browser-level DevTools WebSocket URL
Do not use this guide if your goal is simply:
- start a browser for your agent
- run the normal local PinchTab workflow
For that, use managed instances with pinchtab and POST /instances/start.
Launch vs attach
The mental model is:
launch = PinchTab starts and owns the browser
attach = PinchTab registers an already running browser
With attach:
- Chrome is started somewhere else
- PinchTab receives a
cdpUrl - the server registers that browser as an attached instance
What is implemented today
The current codebase implements:
POST /instances/attach- attach policy in config under
security.attach - attached-instance metadata in
GET /instances
The attach request body is:
{
"name": "shared-chrome",
"cdpUrl": "ws://127.0.0.1:9222/devtools/browser/..."
}
There is currently no CLI attach command.
Step 1: enable attach policy
Attach is disabled unless you allow it in config.
Example:
{
"security": {
"attach": {
"enabled": true,
"allowHosts": ["127.0.0.1", "localhost", "::1"],
"allowSchemes": ["ws", "wss"]
}
}
}
What this does:
- enables the attach endpoint
- restricts which hosts are accepted
- restricts which URL schemes are accepted
What this does not do:
- it does not start Chrome
- it does not define a global remote browser
- it does not replace managed instances
Step 2: start Chrome with remote debugging
Example:
google-chrome --remote-debugging-port=9222
# Or on some systems:
# chromium --remote-debugging-port=9222
This makes Chrome expose a browser-level DevTools endpoint.
Step 3: get the browser WebSocket URL
Query Chrome:
curl -s http://127.0.0.1:9222/json/version | jq .
# Response
{
"webSocketDebuggerUrl": "ws://127.0.0.1:9222/devtools/browser/abc123"
}
The value of webSocketDebuggerUrl is the cdpUrl you pass to PinchTab.
Step 4: attach it to PinchTab
curl -X POST http://localhost:9867/instances/attach \
-H "Content-Type: application/json" \
-d '{
"name": "shared-chrome",
"cdpUrl": "ws://127.0.0.1:9222/devtools/browser/abc123"
}'
# Response
{
"id": "inst_0a89a5bb",
"profileId": "prof_278be873",
"profileName": "shared-chrome",
"port": "",
"headless": false,
"status": "running",
"attached": true,
"cdpUrl": "ws://127.0.0.1:9222/devtools/browser/abc123"
}
Notes:
nameis optional; if omitted, the server generates one likeattached-...- the server validates the URL against
security.attach.allowHostsandsecurity.attach.allowSchemes
Step 5: confirm it is registered
curl -s http://localhost:9867/instances | jq .
# CLI Alternative
pinchtab instances
An attached instance appears in the normal instance list with:
attached: truecdpUrl: ...status: "running"
Ownership and lifecycle
Attached instances are externally owned.
That means:
- PinchTab did not launch the browser
- PinchTab stores metadata about that browser as an instance
- the external Chrome process remains outside PinchTab lifecycle ownership
In practical terms:
- stopping the attached instance in PinchTab unregisters it from the server
- it does not imply that PinchTab launched or can fully manage the external Chrome process
When attach makes sense
Use attach when:
- Chrome is managed by another system
- Chrome is already running in a separate service or container
- you want the server to know about an externally managed browser
- you want to keep browser ownership outside PinchTab
Security
Attach widens the trust boundary, so keep it locked down.
Recommended rules:
- leave attach disabled unless you need it
- keep
allowHostsnarrow - keep
allowSchemesnarrow - set
PINCHTAB_TOKENwhen the server is reachable outside localhost - only attach to CDP endpoints you trust
Also remember:
- Chrome DevTools gives powerful browser control
- a reachable CDP endpoint should be treated as sensitive infrastructure
If Chrome is remote, prefer a tunnel rather than exposing the debugging port broadly.
Operational model
The intended model is:
agent -> PinchTab server -> attached external Chrome
This is an expert path, not the default user path.
The default path remains:
pinchtab
then managed instance start via:
curl -X POST http://localhost:9867/instances/start \
-H "Content-Type: application/json" \
-d '{"mode":"headless"}'
# CLI Alternative
pinchtab instance start