@useswarm/cli
v0.4.0
Published
Swarm CLI — AI-powered UX testing from your terminal
Readme
@useswarm/cli
AI-powered UX testing from your terminal. Run real browser agents against your app — locally or in production — and get actionable feedback in minutes.
Install
npm install -g @useswarm/cliRequires Node.js 18+.
Quick Start
# 1. Authenticate
swarm login
# 2. Run a test (interactive — just answer the prompts)
swarm test
# 3. Or pass everything as flags
swarm test --url localhost:3000 --goal "Sign up for a new account" --agents 3Commands
swarm
Run with no arguments for an interactive menu.
$ swarm
Swarm CLI — AI-powered UX testing
Logged in as Jane (Acme Corp)
What would you like to do?
1) Run a UX test
2) List saved swarms
3) Log outswarm login
Authenticate via your browser using a device code flow.
swarm login # uses default API
swarm login --api-url https://... # custom API endpointswarm logout
Remove stored credentials.
swarm test
Run a UX simulation. All options are interactive when omitted — just run swarm test and follow the prompts.
swarm test [options]Target
| Flag | Description |
|------|-------------|
| --url <url> | Target URL. Use localhost:PORT for local dev |
| --no-tunnel | Skip tunnel (URL must be publicly accessible) |
| --tunnel-provider <provider> | cloudflare, ngrok, or auto (default: auto) |
Test Configuration
| Flag | Description | Default |
|------|-------------|---------|
| --goal <goal> | What the user should try to do | (prompted) |
| --description <desc> | Describe your target audience | general web users |
| --agents <n> | Number of AI agents to generate | 3 |
| --max-steps <n> | Maximum steps per agent | 30 |
| --swarm <id> | Use personas from an existing swarm | |
| --audience <desc> | Audience description for persona generation | |
AI Model
| Flag | Description | Default |
|------|-------------|---------|
| --provider <name> | openai or anthropic | openai |
| --model <name> | Model name override | provider default |
Local Dev Setup
| Flag | Description |
|------|-------------|
| --backend <port\|url> | Separate backend server (e.g. 8080, localhost:8080) |
| --backend-paths <paths> | Additional backend route prefixes (comma-separated) |
When targeting localhost, the CLI automatically:
- Opens a tunnel (Cloudflare or ngrok) so remote AI agents can reach your app
- Detects your framework (Next.js, Vite, Django, etc.) and warns about common pitfalls
- Checks if your dev server is running before opening the tunnel
- Rewrites localhost URLs in responses, cookies, headers, and CSP
Authentication
Three modes — pick the one that matches what your test needs.
Login mode (existing account):
| Flag | Description |
|------|-------------|
| --login-url <url> | Login page URL (e.g. /login) |
| --username <user> | Username or email |
| --password <pass> | Password (insecure — visible in ps) |
| --password-stdin | Read password from stdin (for CI/CD) |
Sign-up mode (no account yet — each persona gets a unique sub-aliased email):
| Flag | Description |
|------|-------------|
| --signup-email <email> | Base email — each persona registers as local+<hash>@domain derived from this |
| --signup-password <pass> | Optional shared password. If omitted, a strong random password is generated per persona-run (not persisted) |
Cookie injection (skip login entirely):
| Flag | Description |
|------|-------------|
| --cookies <file> | Path to a JSON file with session cookies |
| --cookies-stdin | Read cookies JSON from stdin |
| --start-url <url> | URL the agent lands on after auth (recommended with --cookies) |
The interactive prompt masks password input. For scripts:
echo "$PASS" | swarm test --url localhost:3000 --goal "..." --username [email protected] --password-stdinWhen you run swarm test interactively without auth flags, it offers all three modes — and auto-suggests Sign-up when your goal text mentions "sign up", "register", "create account", or "onboard".
Other
| Flag | Description |
|------|-------------|
| -y, --yes | Skip confirmation prompts (non-interactive mode) |
swarm list-swarms
List your saved persona swarms.
swarm list-swarmsLocalhost Testing
The CLI is designed to work with any local dev setup out of the box.
Single Server (Next.js, Nuxt, SvelteKit, Remix)
Most fullstack frameworks serve frontend and API routes on one port. Just point at it:
swarm test --url localhost:3000 --goal "Complete the onboarding flow"The CLI detects fullstack frameworks and warns you if --backend is unnecessary.
Separate Frontend + Backend
If your frontend (port 3000) and API (port 8080) are separate processes:
swarm test --url localhost:3000 --backend 8080The CLI spins up a reverse proxy that routes /api/*, /auth/*, /graphql, /trpc/* to your backend, and everything else to your frontend — all behind a single tunnel URL.
Need custom API paths?
swarm test --url localhost:3000 --backend 8080 --backend-paths "/v1,/socket.io,/webhooks"Tunnel Providers
The CLI supports two tunnel providers for exposing your localhost to the cloud:
Cloudflare Tunnel (default)
Free with no bandwidth limits. Requires the cloudflared binary installed on your machine:
| Platform | Install command |
|----------|----------------|
| macOS | brew install cloudflared |
| Windows | winget install Cloudflare.cloudflared |
| Linux (Debian/Ubuntu) | curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \| sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null && echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" \| sudo tee /etc/apt/sources.list.d/cloudflared.list && sudo apt update && sudo apt install cloudflared |
| Linux (binary) | curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared && chmod +x /usr/local/bin/cloudflared |
| npm (any platform) | npm install -g cloudflared |
No Cloudflare account or API key required — it just works.
ngrok (fallback)
Bundled with the CLI — no extra install needed. Uses your Swarm account's managed ngrok token. Subject to ngrok's bandwidth limits on the free tier.
Choosing a provider
# Auto mode (default) — tries Cloudflare first, falls back to ngrok
swarm test --url localhost:3000 --goal "Sign up"
# Force Cloudflare
swarm test --url localhost:3000 --goal "Sign up" --tunnel-provider cloudflare
# Force ngrok
swarm test --url localhost:3000 --goal "Sign up" --tunnel-provider ngrokWhat the Tunnel Handles
When testing localhost, the CLI automatically:
- URL rewriting — Rewrites
http://localhost:PORTreferences in HTML, JS, JSON, CSS, manifests, and WebSocket URLs so remote browsers can load all resources - Cookie domain stripping — Strips
Domain=localhostfromSet-Cookieheaders so cookies work on the tunnel domain - Header rewriting — Fixes
Locationredirects,Access-Control-Allow-Origin, andContent-Security-Policyheaders - Host header — Sends
Host: localhost:PORTto your server so framework host validation (DjangoALLOWED_HOSTS, Railsconfig.hosts) works - HTTPS — Tunnel is HTTPS-only with
X-Forwarded-Proto: httpsforwarded - WebSocket — Full WebSocket support (HMR, real-time features)
- SSE passthrough — Server-Sent Events are streamed without buffering
Framework Tips
| Framework | Notes |
|-----------|-------|
| Next.js | Don't use --backend — API routes are on the same port. Add allowedOrigins in next.config.js for Server Actions if needed |
| Vite | If you have server.proxy in vite.config.ts, skip --backend — Vite handles it |
| Django | Add the tunnel URL to CSRF_TRUSTED_ORIGINS and ALLOWED_HOSTS |
| Rails | Check config.hosts includes the tunnel hostname, or use config.hosts.clear in development |
Authenticated Testing
Three modes are supported.
Login (existing account)
swarm test --url localhost:3000 --login-url /login --username [email protected]
# Password will be prompted interactively (masked)The AI agent navigates to the login page, fills in credentials, and then performs the test goal. Credentials are encrypted end-to-end (AES-256-GCM) and never stored in plaintext.
Sign-up (one base email, N unique aliases)
For testing sign-up flows: you supply one base email, each persona registers with a unique sub-aliased address derived from it.
swarm test --url localhost:3000 --goal "Sign up for an account" \
--signup-email [email protected] \
--agents 5
# Personas register as:
# [email protected]
# [email protected]
# [email protected]
# ...
# All confirmation emails arrive in your one inbox at [email protected].Each alias is generated at run time as local+<base36(timestamp)+random>@domain:
- The timestamp half guarantees the alias can never be replicated in the future.
- The random half disambiguates personas spawned in the same millisecond.
- The agent is told to type the exact alias verbatim — the standard login pre-fill and login tool are suppressed for sign-up runs (the agent fills the form itself).
- The generated alias is persisted to the run record so confirmation emails can be tied back to a specific persona.
Pass --signup-password to share one password across all personas; omit it to have the runtime mint a strong random password per persona-run (not persisted).
Plus-addressing works with Gmail, Fastmail, and most custom domains.
Cookie injection (skip login)
swarm test --url localhost:3000 --goal "Explore settings" \
--cookies ./cookies.json \
--start-url http://localhost:3000/dashboardCapture the cookies file with the Cookie-Editor browser extension — Export → JSON. When testing localhost, cookie domains captured from a different host are auto-rewritten to match the tunnel.
CI/CD Usage
Run headless with all flags and -y to skip prompts:
swarm test \
--url https://staging.example.com \
--goal "Complete checkout flow" \
--description "Mobile-first shoppers" \
--agents 5 \
--max-steps 40 \
--no-tunnel \
-yWith authentication:
echo "$TEST_PASSWORD" | swarm test \
--url https://staging.example.com \
--goal "Update profile settings" \
--username [email protected] \
--password-stdin \
--no-tunnel \
-yConfiguration
Credentials are stored in ~/.config/swarm/config.json after swarm login. The API URL can be overridden:
# Via login flag
swarm login --api-url https://api.example.com
# Via environment variable
SWARM_API_URL=https://api.example.com swarm testHow It Works
swarm login— Device code auth flow. Opens your browser, you click "Authorize", the CLI receives an API key.swarm test— Creates a test run with AI-generated personas (or from a saved swarm). Each persona is a unique user profile with different demographics, tech literacy, and behavioral traits.Tunnel — For localhost targets, a Cloudflare or ngrok tunnel makes your local server reachable. A reverse proxy handles URL rewriting, cookie fixing, and header translation.
AI Agents — Each persona runs in a real cloud browser (Browserbase). The agent navigates your app, performs the goal, and captures UX observations at every step.
Results — Live-streamed to your terminal via SSE. When all agents finish, you get a synthesis report with prioritized UX issues and a judge verdict.
Requirements
- Node.js 18+
- A Swarm account with a Pro plan (useswarm.co)
- For local testing:
cloudflared(install) or ngrok (bundled)
