> ## Documentation Index
> Fetch the complete documentation index at: https://skyvern.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect Skyvern to Your Local Browser

> Use skyvern browser serve to let Skyvern Cloud control a Chrome browser on your local machine, reusing your existing cookies, sessions, extensions, and saved passwords through a secure tunnel.

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 theme={null}
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.

<Note>
  The `--tunnel` flag requires [ngrok](https://ngrok.com/download) to be installed and authenticated. Run `ngrok authtoken <your-token>` once to set it up.
</Note>

### Step-by-step (manual tunnel)

If you prefer to manage the tunnel yourself:

```bash theme={null}
# 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`:

<CodeGroup>
  ```python Python theme={null}
  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 theme={null}
  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 theme={null}
  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"
    }'
  ```
</CodeGroup>

***

## 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 theme={null}
# 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

<Warning>
  **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.
</Warning>

### 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 theme={null}
skyvern browser serve --api-key "your-skyvern-api-key"
```

Or set it via environment variable:

```bash theme={null}
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](mailto: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](/developers/optimization/browser-sessions)**                            | You want Skyvern Cloud to manage the browser entirely in the cloud                |
| **[Browser Profiles](/developers/optimization/browser-profiles)**                            | You want to save and reuse cookies/storage state across cloud sessions            |
| **[CDP Connect](/developers/self-hosted/browser#cdp-connect-external-chrome)** (self-hosted) | You're running Skyvern locally and want to connect to an existing Chrome instance |

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="ngrok not found">
    Install ngrok from [ngrok.com/download](https://ngrok.com/download) and authenticate it:

    ```bash theme={null}
    ngrok authtoken <your-token>
    ```
  </Accordion>

  <Accordion title="Chrome not found">
    Use `--chrome-path` to specify the path to your Chrome executable:

    ```bash theme={null}
    # 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"
    ```
  </Accordion>

  <Accordion title="Port already in use">
    Another process is using port 9222. Either stop that process or use a different port:

    ```bash theme={null}
    skyvern browser serve --port 8222
    ```
  </Accordion>

  <Accordion title="Tunnel connection drops">
    ngrok free tier tunnels have connection limits. For production use, consider an ngrok paid plan or contact [support@skyvern.com](mailto:support@skyvern.com) for alternative tunnel options.
  </Accordion>
</AccordionGroup>

***

## Next steps

<CardGroup cols={2}>
  <Card title="Browser Sessions" icon="window" href="/developers/optimization/browser-sessions">
    Use cloud-managed browser sessions for multi-step tasks
  </Card>

  <Card title="Browser Profiles" icon="floppy-disk" href="/developers/optimization/browser-profiles">
    Save and reuse authenticated browser state
  </Card>
</CardGroup>
