Elementary OS Deployment of Pinchtab Browser Automation Tool — Full Configuration and Troubleshooting Notes

Background

Pinchtab is a lightweight browser automation tool that provides AI Agent-friendly browser control capabilities via an HTTP API. Compared to Playwright, it reduces token consumption by 5–13×.

Project Repository: GitHub - pinchtab/pinchtab: High-performance browser automation bridge and multi-instance orchestrator with advanced stealth injection and real-time dashboard. · GitHub

Environment

  • OS: Elementary OS 8.1 (based on Ubuntu 24.04)
  • Architecture: ARM64
  • Chromium: Chromium bundled with Playwright

Deployment Steps

1. Install Go

sudo apt update && sudo apt install -y golang-go

2. Fetch Pinchtab Binary

git clone https://github.com/pinchtab/pinchtab.git
cd pinchtab && go build -o pinchtab ./cmd/pinchtab

3. systemd Service Configuration

[Unit]
Description=Pinchtab Browser Automation Service
After=network.target

[Service]
Type=simple
User=$USER
Group=$USER
WorkingDirectory=/opt/pinchtab
ExecStart=/opt/pinchtab/pinchtab
Restart=on-failure
RestartSec=10

Environment="PINCHTAB_PORT=9867"
Environment="PINCHTAB_HEADLESS=true"
Environment="PINCHTAB_PROFILE_DIR=/var/lib/pinchtab/chrome-profile"
Environment="PINCHTAB_STATE_DIR=/var/lib/pinchtab"
Environment="PINCHTAB_AUTO_LAUNCH=1"
Environment="CHROME_BIN=$HOME/.cache/ms-playwright/chromium-1212/chrome-linux/chrome"
Environment="CHROME_FLAGS=--no-sandbox"

NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/var/lib/pinchtab $HOME/.config/pinchtab

MemoryMax=2G
CPUQuota=200%

[Install]
WantedBy=multi-user.target

4. Deploy

sudo mkdir -p /opt/pinchtab /var/lib/pinchtab
sudo chown $USER:$USER /var/lib/pinchtab
sudo cp pinchtab /opt/pinchtab/ && sudo chmod +x /opt/pinchtab/pinchtab
sudo systemctl daemon-reload && sudo systemctl enable --now pinchtab

Key Pitfalls and Solutions

1. chromium-browser Is a Snap Stub

On Ubuntu 24.04, the chromium-browser package is merely a transitional snap wrapper — it contains no actual browser binary. Pinchtab auto-detects it but fails to launch.

Solution: Use Playwright’s bundled Chromium instead, and explicitly specify its path via the CHROME_BIN environment variable:

# Locate Playwright's Chromium binary
find ~/.cache/ms-playwright -name chrome -type f
# Set CHROME_BIN to the path found above

2. AppArmor Sandbox Restrictions

Chrome startup fails with No usable sandbox!. Starting with Ubuntu 23.10, AppArmor restricts unprivileged user namespaces.

Solution: Disable sandboxing via CHROME_FLAGS=--no-sandbox.

3. curl Proxy Interference with localhost

If all_proxy is set system-wide, curl attempts to route localhost requests through the proxy, causing connection failures (exit code 97).

Solution: Add the --noproxy flag to curl commands to bypass proxy for localhost.

4. systemd’s ProtectHome Blocks Chromium Access

Setting ProtectHome=true prevents the service from accessing Playwright’s Chromium binary located in the user’s home directory.

Solution: Use ProtectHome=read-only, which permits read access while blocking writes.

Measured Token Efficiency

Test page: play.wenpai.net

Mode Characters Estimated Tokens Savings
Text extraction (/text) 769 ~192 94%
Interactive snapshot (?filter=interactive) 1,995 ~498 85%
Full snapshot (/snapshot) 13,157 ~3,289 Baseline

In text mode, a full webpage requires only ~192 tokens to retrieve all content — a 94% reduction compared to Playwright’s full snapshot (~3,289 tokens).

Usage Examples

# Health check
curl --noproxy localhost http://localhost:9867/health

# Navigate to a webpage
curl --noproxy localhost -X POST http://localhost:9867/navigate \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}'

# Extract text (~192 tokens)
curl --noproxy localhost http://localhost:9867/text

# Interactive snapshot (~498 tokens)
curl --noproxy localhost "http://localhost:9867/snapshot?filter=interactive"

# Take screenshot
curl --noproxy localhost http://localhost:9867/screenshot > screenshot.jpg

Summary

Pinchtab has been successfully deployed and runs stably under systemd on Elementary OS (Ubuntu 24.04 ARM64). Four key points enabled success:

  1. Use Playwright’s Chromium instead of the snap stub — Ubuntu 24.04’s chromium-browser package is only a snap wrapper.
  2. Bypass AppArmor with --no-sandbox — Ubuntu 23.10+ restricts unprivileged user namespaces.
  3. Use curl --noproxy to avoid proxy interference — Required when accessing localhost under a system-wide proxy configuration.
  4. Set ProtectHome=read-only — Allows the systemd service to read Chromium binaries stored in the user’s home directory without granting write access.

Real-world measurements show 85–94% higher token efficiency versus traditional approaches — making Pinchtab exceptionally well-suited for AI Agent-driven browser automation.

This deployment process has been verified on Ubuntu 24.04 (Wenpai VM). Additionally, here’s an extra observation regarding snap-installed Chromium:

Snap Wrapper vs. Actual Binary

Elementary OS notes that chromium-browser is a snap “wrapper” (a thin shell), and recommends using Playwright Chromium instead. However, if the VM cannot directly access the internet to download Playwright Chromium (e.g., in our cluster environment where all traffic goes through a proxy), there’s an alternative:

Use the actual Chromium binary inside the snap package directly—bypassing the snap wrapper entirely:

# Snap wrapper (does NOT work — chromedp cannot control it)
/snap/bin/chromium

# Actual binary inside the snap (works)
/snap/chromium/current/usr/lib/chromium-browser/chrome

The snap wrapper launches its own sandbox environment, which conflicts with chromedp’s process management. Calling the internal binary directly skips the snap sandbox layer.

NO_PROXY Configuration

The original post mentions that curl requires the --noproxy flag, but the pinchtab CLI itself is also affected by the all_proxy environment variable. To resolve this comprehensively, set NO_PROXY=localhost,127.0.0.1 directly in /etc/profile.d/, ensuring it applies system-wide:

# /etc/profile.d/pinchtab.sh
export CHROME_BIN=/snap/chromium/current/usr/lib/chromium-browser/chrome
export PINCHTAB_HEADLESS=true
export PINCHTAB_AUTO_LAUNCH=1
export NO_PROXY=localhost,127.0.0.1

Profile Creation

In Dashboard mode, a profile must first be created via API before launching an instance; the CLI does not provide a direct command for profile creation:

curl --noproxy '*' -s -X POST http://127.0.0.1:9867/profiles \
  -H 'Content-Type: application/json' -d '{"name":"default"}'

With PINCHTAB_AUTO_LAUNCH=1 set, the service will automatically launch an instance upon startup—no manual start command required.

Access to sites such as wenpai.org has been verified and works correctly.

Deployment and verification on Fedora 43 (ARM64) have also been completed; here are several additional findings.

Environmental Differences

The chromium-browser installed via dnf on Fedora is a genuine binary—unlike Ubuntu’s Snap-based “shell” package. Systemd manages services using user-level services, and DevOps has deployed the solution uniformly across the entire cluster.

PINCHTAB_AUTO_LAUNCH=1 Is Mandatory

The systemd service deployed by DevOps omits this environment variable. Without it, the service starts only in dashboard mode—no browser instance is launched, and all nav/text/snap commands return 503: no running instances.

To work around this, you must manually create a profile and launch it via the API:

curl --noproxy '*' -s -X POST http://127.0.0.1:9867/profiles \
  -H 'Content-Type: application/json' -d '{"name":"default"}'

curl --noproxy '*' -s -X POST http://127.0.0.1:9867/profiles/default/start \
  -H 'Content-Type: application/json'

After adding PINCHTAB_AUTO_LAUNCH=1, restarting the service automatically launches the browser instance—no manual intervention required.

CLI text Command Bug

The pinchtab nav command works correctly and returns the proper tab ID. However, pinchtab text consistently fails with tab tab_xxx not found, attempting to access an outdated, non-existent tab ID that does not match the one returned by nav.

Reproduction Steps:

pinchtab nav https://example.com   # Succeeds, returns tab_abc123
pinchtab text                       # Fails, attempts to access tab_xyz789 (nonexistent)

Workaround: Bypass the CLI and use the instance’s HTTP API directly:

# First navigate via API
curl --noproxy '*' -s -X POST http://127.0.0.1:9868/navigate \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com"}'

# Then retrieve text (works correctly)
curl --noproxy '*' -s http://127.0.0.1:9868/text

Note: The instance port is 9868 (not the dashboard port 9867).

Token Efficiency Verification

Testing against the Cyber Forum homepage confirms that the /text endpoint is highly token-efficient—the full page content compresses to just a few hundred tokens, significantly more concise than Scrapling MCP’s Markdown output. This makes it ideal for AI agents needing rapid, lightweight page content extraction.

Summary

Item Status
Service startup :white_check_mark: systemd user service
Navigation :white_check_mark: nav command works
Text extraction :warning: CLI bug present; API works fine
Auto-launch :white_check_mark: Functions correctly with AUTO_LAUNCH=1
Token efficiency :white_check_mark: 85–94% more efficient than traditional approaches