Skip to main content
PinchTab instances can run Chrome in two modes: Headless (no visible window) and Headed (visible browser window).

Quick Comparison

Headless Mode

No visible window, fast, lightweight, perfect for production automation

Headed Mode

Visible browser window, slower, debuggable, ideal for development

Headless Mode (Default)

Chrome runs without a visible window. All interactions happen via API.

Starting Headless Instance

# CLI (headless is default)
pinchtab instance start

# API (explicit)
curl -X POST http://localhost:9867/instances/start \
  -H "Content-Type: application/json" \
  -d '{"mode": "headless"}'
Response:
{
  "id": "inst_0a89a5bb",
  "port": "9868",
  "headless": true,
  "status": "starting"
}

Headless Characteristics

Advantages:
  • No UI overhead — No window rendering, faster operations
  • Lightweight — Lower CPU/memory usage (50-70% of headed)
  • Scriptable — Perfect for automation, CI/CD, unattended workflows
  • Remote-friendly — Works over SSH, Docker, cloud servers
  • Scalable — Run 10+ instances on modest hardware
Disadvantages:
  • No visual feedback — Can’t see what’s happening
  • Harder to debug — Must rely on screenshots/logs
  • Different rendering — Some sites detect headless mode

Headless Use Cases

Production Automation

AI agents, form filling, data extraction

CI/CD Pipelines

Testing, scraping, report generation

Cloud Deployment

VPS, Lambda, container orchestration

Batch Processing

Long-running tasks, scheduled jobs

Headed Mode

Chrome runs with a visible window that you can see and interact with.

Starting Headed Instance

# CLI
pinchtab instance start --mode headed

# API
curl -X POST http://localhost:9867/instances/start \
  -d '{"mode": "headed"}'
Response:
{
  "id": "inst_1b9a5dcc",
  "port": "9869",
  "headless": false,
  "status": "starting"
}

Headed Characteristics

Advantages:
  • Visual feedback — See exactly what’s happening in real-time
  • Easy debugging — Watch browser, inspect elements, debug flows
  • Interactive — Manually click, type, scroll in window
  • Development-friendly — Perfect for testing and prototyping
  • Realistic — Harder for sites to detect as bot
Disadvantages:
  • Slower — Window rendering adds 2-3x latency
  • Requires display — Needs X11/Wayland on Linux, native desktop on macOS/Windows
  • Resource-heavy — More CPU/memory for rendering
  • Not scalable — Limited by display server capacity

Headed Use Cases

Development

Build and test automation scripts

Debugging

Watch and modify behavior in real-time

Demonstrations

Show automation to stakeholders

Manual Collaboration

Human guides the automation

Side-by-Side Comparison

AspectHeadlessHeaded
Visibility❌ Invisible✅ Visible window
Speed✅ Fast❌ Slower (2-3x)
Resource usage✅ Light❌ Heavy
Debugging❌ Hard✅ Easy
Display required❌ No✅ Yes
Automation✅ Perfect⚠️ Can interact manually
CI/CD✅ Ideal❌ Not practical
Development⚠️ Possible✅ Recommended
Production✅ Recommended❌ Not recommended

When to Use Each

Use Headless For:

  • ✅ Production automation (scripts, agents, workflows)
  • ✅ CI/CD pipelines (GitHub Actions, GitLab CI)
  • ✅ Unattended execution (servers, containers, cloud)
  • ✅ High-throughput tasks (scraping 1000s of pages)
  • ✅ Cost-sensitive environments (minimize resources)
  • ✅ Long-running processes (24/7 automation)
# Production: headless instances
for i in 1 2 3; do
  pinchtab instance start --mode headless
done

# List all
curl http://localhost:9867/instances | jq '.[] | {id, port, headless}'

Use Headed For:

  • ✅ Local development (debugging scripts)
  • ✅ Testing automation behavior
  • ✅ Demonstrating workflows to humans
  • ✅ Prototyping and experimentation
  • ✅ Interactive debugging (pause and inspect)
  • ✅ Manual verification before production
# Development: headed instance
pinchtab profile create dev
pinchtab instance start --profileId dev --mode headed

Display Requirements

macOS

Native window system — headed instances work out of the box:
pinchtab instance start --mode headed
# Browser window appears immediately

Linux

Headless instances: Work anywhere (no display needed) Headed instances: Require X11 or Wayland display server
# Check if display available
echo $DISPLAY
# :0 or :1 (good)
# empty (no display — use headless)

# Start headed instance
DISPLAY=:0 pinchtab instance start --mode headed

Windows

Native window system — headed instances work out of the box:
pinchtab instance start --mode headed
# Browser window appears

Docker (Headless)

Recommended approach:
FROM pinchtab/pinchtab:latest
CMD ["pinchtab"]
# Run container
docker run -d -p 9867:9867 pinchtab/pinchtab

# Create headless instances
curl -X POST http://localhost:9867/instances/start \
  -d '{"mode":"headless"}'

Docker (Headed - Advanced)

Requires X11 forwarding:
# Allow X11 connections
xhost +local:docker

# Run with display forwarding
docker run \
  -e DISPLAY=$DISPLAY \
  -v /tmp/.X11-unix:/tmp/.X11-unix:rw \
  -p 9867:9867 \
  pinchtab/pinchtab

# Create headed instance
curl -X POST http://localhost:9867/instances/start \
  -d '{"mode":"headed"}'
# Browser window appears on host
Headed mode in Docker is complex and not recommended for production

Development Workflow

Step 1: Debug with Headed

# Terminal 1: Start orchestrator
pinchtab

# Terminal 2: Create headed instance
DEV=$(pinchtab instance start --mode headed | jq -r .id)

# Terminal 3: Build automation
curl -X POST http://localhost:9867/instances/$DEV/tabs/open \
  -d '{"url":"https://example.com"}'

# Watch browser window as you develop
# Iterate until automation works correctly

Step 2: Test with Headless

# Stop headed instance
pinchtab instance stop $DEV

# Create headless instance
PROD=$(pinchtab instance start --mode headless | jq -r .id)

# Run same automation
curl -X POST http://localhost:9867/instances/$PROD/tabs/open \
  -d '{"url":"https://example.com"}'

# Verify it works without visual debugging

Step 3: Deploy to Production

# Production: Always headless
BRIDGE_HEADLESS=true pinchtab

Performance Comparison

Speed Test

#!/bin/bash

# Test headless
start=$(date +%s%N)
HEADLESS=$(pinchtab instance start --mode headless | jq -r .id)
sleep 5  # Wait for Chrome init
end=$(date +%s%N)
headless_time=$(( (end - start) / 1000000 ))
echo "Headless init: ${headless_time}ms"

# Test headed
start=$(date +%s%N)
HEADED=$(pinchtab instance start --mode headed | jq -r .id)
sleep 5  # Wait for Chrome init
end=$(date +%s%N)
headed_time=$(( (end - start) / 1000000 ))
echo "Headed init: ${headed_time}ms"

echo "Overhead: $((headed_time - headless_time))ms"
# Typical: 2000-5000ms overhead for headed

Resource Usage

ModeCPU (idle)MemoryStartup Time
Headless5-10%100-150 MB3-8 seconds
Headed15-25%200-300 MB5-12 seconds
// Source: internal/orchestrator/orchestrator.go:107-116
// Instance timeout configuration:
// - Allows 60 seconds for operations
// - Accounts for Chrome initialization (8-20s)
// - Navigation timeout (up to 60s)
client: &http.Client{Timeout: 60 * time.Second}

Mixed Mode Setup

Run both headless and headed instances simultaneously:
# Start orchestrator
pinchtab

# Production: Multiple headless instances
for i in 1 2 3; do
  curl -s -X POST http://localhost:9867/instances/start \
    -d '{"mode":"headless"}'
done

# Development: One headed instance
curl -s -X POST http://localhost:9867/instances/start \
  -d '{"mode":"headed"}'

# View all instances
curl http://localhost:9867/instances | \
  jq '.[] | {id, port, mode: (if .headless then "headless" else "headed" end)}'
Output:
{"id":"inst_xxx","port":"9868","mode":"headless"}
{"id":"inst_yyy","port":"9869","mode":"headless"}
{"id":"inst_zzz","port":"9870","mode":"headless"}
{"id":"inst_aaa","port":"9871","mode":"headed"}

Dashboard Integration

The dashboard shows mode for each instance:
  • Headless: No window, status badge only
  • Headed: Live browser window preview (if available)
# View in dashboard
open http://localhost:9867/dashboard

# Instances tab shows:
# - Mode column (headless/headed)
# - Visual indicator
# - Window preview for headed instances

Troubleshooting

Headed Instance Not Opening Window

Cause: Display server not available Solution:
# Linux: Check DISPLAY
echo $DISPLAY

# If empty, use headless instead
pinchtab instance start --mode headless

# Or set up X11 forwarding
ssh -X user@server

Headed Instance Too Slow

Cause: Window rendering overhead Solution:
# Use headless for production
pinchtab instance start --mode headless

# Use headed only for debugging

Headless Instance But Need to Debug

Solution: Use API operations to inspect:
# Get page structure
curl http://localhost:9867/tabs/$TAB/snapshot | jq .

# Take screenshot
curl http://localhost:9867/tabs/$TAB/screenshot > page.png

# Get page text
curl http://localhost:9867/tabs/$TAB/text

# Evaluate JavaScript
curl -X POST http://localhost:9867/tabs/$TAB/evaluate \
  -d '{"expression":"document.title"}'

Best Practices

Default to Headless

# Production config
BRIDGE_HEADLESS=true pinchtab

Use Headed for Development Only

# Local development
pinchtab instance start --mode headed

# Production deployment
pinchtab instance start --mode headless

Test Both Modes

# Develop with headed
DEV=$(pinchtab instance start --mode headed | jq -r .id)
# ... build automation ...

# Verify with headless
PROD=$(pinchtab instance start --mode headless | jq -r .id)
# ... run same automation ...
# Ensure both work identically

Minimize Headed Usage

# Start headed only when needed
# Stop immediately when done
pinchtab instance stop $HEADED_ID

Next Steps

Browser Instances

Learn about instance lifecycle

Stealth Mode

Bypass bot detection in headless

Docker Deployment

Run headless in containers

Common Patterns

Automate with headless mode

Build docs developers (and LLMs) love