Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.useswarm.co/llms.txt

Use this file to discover all available pages before exploring further.

Persistent Tunnels

Swarm can reuse the same public tunnel hostname for local tests instead of creating a new temporary URL on every run. Persistent tunnels are useful when your app depends on callback URLs, redirect URLs, or OAuth flows that break when the public tunnel URL changes.
Persistent tunnels are provisioned automatically after swarm login or useswarm-mcp login when your Swarm workspace has the feature enabled. If provisioning is unavailable, local tests keep using Cloudflare Quick Tunnels automatically.

How it works

When persistent tunneling is enabled, Swarm assigns one stable hostname to your user and organization:
<user-id>-<org-slug>.swarmtunnel.com
For every local test, the CLI or MCP server:
  1. Starts Swarm’s local proxy in front of your app.
  2. Opens a Cloudflare named tunnel to that proxy.
  3. Reuses your stable hostname for the test URL.
  4. Runs Swarm’s cloud agents against that hostname.
  5. Closes the local tunnel process when the test is done.
The local proxy behavior is the same as normal local testing: split frontend/backend routing, auth-origin rewriting, and localhost URL rewriting still work.

CLI usage

Log in normally:
swarm login
If your account can provision a persistent tunnel, login prints the hostname:
Persistent tunnel created
Hostname: https://<user-id>-<org-slug>.swarmtunnel.com
Run local tests the same way you already do:
swarm test --url localhost:3000 --goal "Sign up for an account"
When the stored persistent tunnel is available, Swarm uses it automatically.

Manual retry or revoke

Retry provisioning:
swarm setup-tunnel
Revoke the current tunnel and clear local tunnel credentials:
swarm setup-tunnel --revoke
After revocation, local tests fall back to temporary tunnels until you provision again.

MCP usage

The MCP package uses the same persistent tunnel flow.
npx @useswarm/mcp login
npx @useswarm/mcp setup-tunnel
npx @useswarm/mcp setup-tunnel --revoke
Inside Claude Code, Cursor, or another MCP host, dev_test automatically uses the persistent hostname when testing localhost.

OAuth and localhost callbacks

OAuth providers often receive localhost callback URLs during development:
https://accounts.example.com/oauth?redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fcallback
That URL is valid on your machine, but many providers require the exact callback origin to be allowlisted. When Swarm runs through a persistent tunnel, the browser agent rewrites common redirect params such as redirect_uri, callbackURL, redirectTo, and returnTo to your stable tunnel hostname before the provider receives the request:
https://accounts.example.com/oauth?redirect_uri=https%3A%2F%2F<user-id>-<org-slug>.swarmtunnel.com%2Fauth%2Fcallback
Swarm also rewrites provider redirect responses that point back to localhost:
http://localhost:3000/auth/callback?code=abc
to:
https://<user-id>-<org-slug>.swarmtunnel.com/auth/callback?code=abc
The rewrite preserves the callback path, query string, and hash. Your app still receives the request through the tunnel and local proxy. If your OAuth provider requires HTTPS callback URLs and does not allow localhost, add the persistent HTTPS callback URL to the provider allowlist once:
https://<user-id>-<org-slug>.swarmtunnel.com/auth/callback
Because the hostname is stable, you do not need to update the allowlist for every test run.
Use test OAuth apps and test accounts for Swarm runs. Do not use production credentials for automated development testing.

Split frontend/backend apps

Persistent tunnels still support split frontend/backend setups:
swarm test \
  --url localhost:3000 \
  --backend localhost:8080 \
  --goal "Create a project"
Swarm opens one tunnel to the local proxy. The proxy routes API paths to the backend and everything else to the frontend. Default backend paths:
PathDestination
/api/*Backend
/auth/*Backend
/graphqlBackend
/trpc/*Backend
Everything elseFrontend
Use --backend-paths for custom backend prefixes.

One active session

Only one active test session can use a persistent tunnel at a time. If a second local test starts while the first still holds the tunnel, Swarm returns a clear conflict message. If a client crashes, Swarm automatically treats the lease as stale after missed heartbeats and lets the next run recover.

Troubleshooting

Login says persistent tunnel was not provisioned

Your test can still run. Swarm falls back to temporary Cloudflare Quick Tunnels. Try again later:
swarm setup-tunnel

A second test says the tunnel is already in use

Wait for the first run to finish, call dev_close in your MCP host, or revoke and re-provision:
swarm setup-tunnel --revoke
swarm setup-tunnel

OAuth redirects still fail

Check which callback URL your provider receives in redirect_uri or sends back in Location. Localhost callback values are rewritten automatically. HTTPS provider allowlists still need to include the stable tunnel callback if the provider does not allow localhost redirect URIs.

Operator setup

Self-hosted or internal deployments need Cloudflare credentials on the Swarm API before users can provision persistent tunnels. See the repository operator runbook at docs/persistent-tunnels.md.