Agents & Automation
shellroute run wraps any command with a proxy session. The session starts, your command runs with all HTTP traffic routed through the exit IP, and the session ends when the command exits. No interactive shell needed.
The core pattern
# Country as positional arg — simplest form
shellroute run US -- curl -s https://httpbin.org/ip
# Datacenter IP (cheaper, $1/GB instead of $3/GB)
shellroute run --iptype datacenter DE -- python check_api.py
# Target a specific city
shellroute run --country US --city "New York" -- node verify.js
# Keep same IP if connection drops (long tasks)
shellroute run --sticky GB -- python monitor.py
# Clean output for piping (no session summary)
shellroute run --no-stat JP -- curl -s https://ipinfo.io/ip Authentication for agents
Three ways to authenticate agents and scripts:
Direct login (non-interactive)
Same OTP flow as shellroute login, but with flags instead of prompts. The agent requests the code, a human provides it, the agent verifies and stores the key.
# Step 1: agent requests code
shellroute login --email [email protected] --request-code
# Step 2: check email for the code
# Step 3: verify the code
shellroute login --email [email protected] --verify-code 847291
# Step 4: get the key for env var / CI secrets
shellroute reveal-key Env var
Set once, all commands use it. Get the key with shellroute reveal-key from any logged-in machine.
export SHELLROUTE_API_KEY=pk_29f6a...
shellroute run US -- python step1.py
shellroute run DE -- python step2.py Inline flag
Per-invocation, nothing stored on disk.
shellroute --api-key pk_29f6a... run US -- curl https://httpbin.org/ip Why agents need scoped proxy access
Per-task isolation
Each shellroute run gets its own session and exit IP. Multiple agents run in parallel without interfering with each other or the host.
No system-wide changes
Only the wrapped command is proxied. The orchestrator, databases, APIs, and other processes keep their direct connections.
Automatic cleanup
Session ends when the command exits. Orphaned sessions are cleaned up after 5 minutes if the process crashes.
Kill switch
If the tunnel drops, requests fail (connection refused) instead of leaking to the host IP.
Examples
Browser automation (Playwright)
# Test from London, datacenter IP
shellroute run --country GB --city London --iptype datacenter -- \
npx playwright test geo-check.spec.ts Multi-country comparison
# Compare pricing from three countries, clean output
shellroute run --no-stat US -- python check_price.py --market us
shellroute run --no-stat DE -- python check_price.py --market de
shellroute run --no-stat JP -- python check_price.py --market jp Long-running with sticky IP
# Keep same IP across reconnects for session consistency
shellroute run --sticky --country US --city "New York" -- \
python long_running_monitor.py Parallel agents
shellroute run US -- python agent.py --region us &
shellroute run --iptype datacenter DE -- python agent.py --region de &
shellroute run --country JP --city Tokyo -- python agent.py --region jp &
wait Pipe proxy output to local processing
# Fetch through proxy, process locally
US_IP=$(shellroute run --no-stat US -- curl -s https://ipinfo.io/ip)
echo "US exit: $US_IP"
# Multi-step: proxy → direct → proxy
shellroute run US -- python fetch_data.py
python process_locally.py # no proxy
shellroute run DE -- python upload_results.py Python integration
Call shellroute run as a subprocess. The agent code doesn't need to know about proxies.
import subprocess
def run_proxied(country, cmd, city=None, iptype=None):
args = ["shellroute", "run", "--no-stat"]
if city:
args += ["--city", city]
if iptype:
args += ["--iptype", iptype]
args += [country, "--"] + cmd
return subprocess.run(args, capture_output=True, text=True)
# Residential from New York
r = run_proxied("US", ["curl", "-s", "https://httpbin.org/ip"], city="NYC")
# Datacenter from Germany
r = run_proxied("DE", ["python", "check.py"], iptype="datacenter") CI/CD pipelines
shellroute needs one environment variable: SHELLROUTE_API_KEY. Get the key from any machine where you've logged in with shellroute reveal-key, then add it as a secret in your CI provider.
GitHub Actions
env:
SHELLROUTE_API_KEY: ${{ secrets.SHELLROUTE_API_KEY }}
steps:
- run: npm install -g shellroute
- name: Geo test from US (residential)
run: shellroute run US -- npm run test:geo
- name: Geo test from DE (datacenter)
run: shellroute run --iptype datacenter DE -- npm run test:geo
- name: Capture US IP
run: |
echo "US_IP=$(shellroute run --no-stat US -- curl -s https://ipinfo.io/ip)" >> $GITHUB_ENV Any CI (GitLab, CircleCI, etc.)
# Set in your CI's secret/env config, then:
npm install -g shellroute # or: brew install shellroute/tap/shellroute
shellroute run US -- your-test-command
# Or pass the key inline (no env var needed)
shellroute --api-key $SHELLROUTE_API_KEY run US -- your-test-command