--- title: Connect Skyvern to Your Local Browser subtitle: Run automations using your existing cookies, logins, and extensions slug: optimization/browser-tunneling --- Want Skyvern Cloud to automate a site where you're already logged in? With `skyvern browser serve`, Skyvern Cloud can control a Chrome browser running on your machine — using your existing cookies, sessions, extensions, and saved passwords. **Common use cases:** - Automate sites where you're already authenticated (no need to re-login) - Reach internal tools behind a VPN or firewall - Use browser extensions you've already installed (ad blockers, auth tools, etc.) - Keep all browser data on your own machine --- ## Quick start One command starts Chrome on your machine and creates a tunnel so Skyvern Cloud can connect: ```bash skyvern browser serve --tunnel ``` That's it. The CLI launches Chrome, starts a local proxy server, and opens an ngrok tunnel. You'll see a tunnel URL in the output — pass it as `browser_address` when running tasks. The `--tunnel` flag requires [ngrok](https://ngrok.com/download) to be installed and authenticated. Run `ngrok authtoken ` once to set it up. ### Step-by-step (manual tunnel) If you prefer to manage the tunnel yourself: ```bash # 1. Start the browser server skyvern browser serve # 2. In a separate terminal, create a tunnel ngrok http 9222 # 3. Copy the ngrok URL and use it as browser_address in your task ``` --- ## Run a task on your local browser Once the tunnel is running, pass the tunnel URL as `browser_address`: ```python Python import asyncio from skyvern import Skyvern async def main(): client = Skyvern(api_key="YOUR_API_KEY") result = await client.run_task( prompt="Download the latest invoice from my account", browser_address="wss://abc123.ngrok-free.dev", ) print(f"Status: {result.status}") print(f"Output: {result.output}") asyncio.run(main()) ``` ```typescript TypeScript import { Skyvern } from "@skyvern/client"; async function main() { const client = new Skyvern({ apiKey: process.env.SKYVERN_API_KEY! }); const result = await client.runTask({ body: { prompt: "Download the latest invoice from my account", browser_address: "wss://abc123.ngrok-free.dev", }, waitForCompletion: true, }); console.log(`Status: ${result.status}`); console.log(`Output: ${JSON.stringify(result.output)}`); } main(); ``` ```bash cURL curl -X POST "https://api.skyvern.com/v1/run/tasks" \ -H "x-api-key: $SKYVERN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Download the latest invoice from my account", "browser_address": "wss://abc123.ngrok-free.dev" }' ``` --- ## How it works ``` ┌──────────────────────────────────────────────────────┐ │ Your machine │ │ │ │ ┌────────────┐ CDP (internal) ┌──────────────┐ │ │ │ Chrome │◄─────────────────►│ Unified │ │ │ │ (port │ port 10222 │ Server │ │ │ │ 10222) │ │ (port 9222) │ │ │ └────────────┘ └──────┬───────┘ │ │ │ │ └──────────────────────────────────────────┼───────────┘ │ ngrok / tunnel│ │ ┌──────▼───────┐ │ Skyvern Cloud│ └──────────────┘ ``` `skyvern browser serve`: 1. **Launches Chrome** with CDP (Chrome DevTools Protocol) enabled on an internal port 2. **Starts a proxy server** on the exposed port (default `9222`) that forwards CDP traffic to Chrome 3. **Optionally creates a tunnel** (`--tunnel`) so Skyvern Cloud can reach it from the internet --- ## CLI options | Option | Default | Description | |---|---|---| | `--port` | `9222` | Port for the proxy server. Chrome uses `port + 1000` internally. | | `--profile-dir` | `~/.skyvern/chrome-profile` | Chrome user data directory. Point this at an existing profile to reuse cookies and logins. | | `--download-dir` | `~/.skyvern/downloads/{browser_id}` | Directory for browser downloads. | | `--api-key` | (none) | API key for authenticating incoming requests. See [Security](#security). | | `--headless` | `false` | Run Chrome in headless mode (no visible window). | | `--chrome-path` | (auto-detect) | Path to Chrome/Chromium executable. | | `--tunnel` | `false` | Automatically start an ngrok tunnel. Requires `ngrok` installed. | | `--json` | `false` | Output connection info as JSON (for scripting). Cannot combine with `--tunnel`. | The `--api-key` option can also be set via the `SKYVERN_BROWSER_SERVE_API_KEY` environment variable. ### Examples ```bash # Use a specific Chrome profile (reuse your existing logins) skyvern browser serve --profile-dir ~/Library/Application\ Support/Google/Chrome/Default # Run headless with auto-tunnel skyvern browser serve --headless --tunnel # Custom port with API key authentication skyvern browser serve --port 8222 --api-key "my-secret-key" # Output connection info as JSON (useful for scripting) skyvern browser serve --json ``` --- ## Security **Read this section before exposing your browser to the internet.** When you run `skyvern browser serve` without `--api-key` and expose it via a tunnel, **anyone with the tunnel URL has full remote control of your Chrome browser**. This includes access to all logged-in sessions, cookies, saved passwords, and anything visible in the browser. ### API key authentication Use your Skyvern API key (from [Settings](https://app.skyvern.com/settings)) with the `--api-key` flag to require authentication on every incoming request: ```bash skyvern browser serve --api-key "your-skyvern-api-key" ``` Or set it via environment variable: ```bash export SKYVERN_BROWSER_SERVE_API_KEY="your-skyvern-api-key" skyvern browser serve ``` When enabled, all requests without a valid `x-api-key` header receive a `401 Unauthorized` response. Skyvern Cloud automatically sends the correct API key when connecting. ### Additional security measures The built-in API key provides basic protection. For additional security such as IP allowlisting, mTLS, or VPN-based access, contact **support@skyvern.com**. --- ## When to use this vs other options | Approach | When to use | |----------|-------------| | **Connect to your local browser** (`skyvern browser serve`) | You want Skyvern Cloud to use your local browser with your existing sessions | | **[Browser Sessions](/optimization/browser-sessions)** | You want Skyvern Cloud to manage the browser entirely in the cloud | | **[Browser Profiles](/optimization/browser-profiles)** | You want to save and reuse cookies/storage state across cloud sessions | | **[CDP Connect](/self-hosted/browser#cdp-connect-external-chrome)** (self-hosted) | You're running Skyvern locally and want to connect to an existing Chrome instance | --- ## Troubleshooting Install ngrok from [ngrok.com/download](https://ngrok.com/download) and authenticate it: ```bash ngrok authtoken ``` Use `--chrome-path` to specify the path to your Chrome executable: ```bash # macOS skyvern browser serve --chrome-path "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" # Linux skyvern browser serve --chrome-path /usr/bin/google-chrome # Windows skyvern browser serve --chrome-path "C:\Program Files\Google\Chrome\Application\chrome.exe" ``` Another process is using port 9222. Either stop that process or use a different port: ```bash skyvern browser serve --port 8222 ``` ngrok free tier tunnels have connection limits. For production use, consider an ngrok paid plan or contact support@skyvern.com for alternative tunnel options. --- ## Next steps Use cloud-managed browser sessions for multi-step tasks Save and reuse authenticated browser state