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

# Quickstart

> Configure your credentials, open a page in a cloud browser, and stop the session.

Open Google in a cloud browser using a Surfsky SDK or your existing automation framework.

<span id="credentials" />

## Before you start

Get your API token and API base URL from the [Surfsky dashboard](https://app.surfsky.io). Replace `YOUR_API_TOKEN` and `https://YOUR_API_HOST` below with your account's values.

```bash theme={null}
export SURFSKY_API_TOKEN="YOUR_API_TOKEN"
export SURFSKY_API_BASE_URL="https://YOUR_API_HOST"
```

Keep the token in your server environment, outside source control. These examples omit `proxy` to use the default pool available to your account. If your account has no pool, provide your own proxy as described in [Proxies](/proxies).

## SDK quickstart

<Tabs>
  <Tab title="Python">
    Requires Python 3.12 or newer.

    <CodeGroup>
      ```bash pip theme={null}
      pip install surfsky
      ```

      ```bash uv theme={null}
      uv init # For a new project
      uv add surfsky
      ```
    </CodeGroup>

    Save as `first_browser.py`:

    ```python theme={null}
    import asyncio
    from surfsky import AsyncSurfsky


    async def main():
        # Or: AsyncSurfsky(api_token="YOUR_API_TOKEN", base_url="https://YOUR_API_HOST")
        async with AsyncSurfsky() as client:
            async with client.browser() as browser:
                await browser.goto("https://www.google.com")
                print(await browser.title())


    asyncio.run(main())
    ```

    <CodeGroup>
      ```bash Python theme={null}
      python first_browser.py
      ```

      ```bash uv theme={null}
      uv run first_browser.py
      ```
    </CodeGroup>
  </Tab>

  <Tab title="JavaScript / TypeScript">
    Requires Node.js 22+ or Bun.

    <CodeGroup>
      ```bash npm theme={null}
      npm install surfsky
      ```

      ```bash Bun theme={null}
      bun add surfsky
      ```
    </CodeGroup>

    Save as `first-browser.mjs`:

    ```javascript theme={null}
    import { Surfsky } from "surfsky";

    // Or: new Surfsky({ apiToken: "YOUR_API_TOKEN", baseUrl: "https://YOUR_API_HOST" });
    const client = new Surfsky();
    const browser = await client.browser();
    try {
      await browser.goto("https://www.google.com");
      console.log(await browser.title());
    } finally {
      await browser.close();
    }
    ```

    <CodeGroup>
      ```bash Node.js theme={null}
      node first-browser.mjs
      ```

      ```bash Bun theme={null}
      bun first-browser.mjs
      ```
    </CodeGroup>
  </Tab>
</Tabs>

Both examples stop the session on completion or error. If cleanup fails, the browser stops after its [inactivity timeout](/sessions#how-a-session-ends).

<span id="choose-an-integration" />

<span id="full-guides" />

## Connect your existing code

Follow the guide for your framework:

* [Playwright](/quickstart/playwright)
* [Puppeteer](/quickstart/puppeteer)
* [Selenium](/quickstart/selenium)
* [chromedp](/quickstart/chromedp)
* [Scrapy](/quickstart/scrapy)

## Using the API directly

### 1. Start a browser

<Tabs>
  <Tab title="One-time">
    ```bash theme={null}
    curl --fail-with-body "$SURFSKY_API_BASE_URL/profiles/one_time" \
      -H "X-Cloud-Api-Token: $SURFSKY_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{}'
    ```
  </Tab>

  <Tab title="Persistent">
    Create a profile once:

    ```bash theme={null}
    curl --fail-with-body "$SURFSKY_API_BASE_URL/profiles" \
      -H "X-Cloud-Api-Token: $SURFSKY_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"title": "My profile", "fingerprint": {"os": "win"}}' # os: win, mac, or android
    ```

    Replace `PROFILE_UUID` with `data.uuid` from the response, then start it:

    ```bash theme={null}
    curl --fail-with-body "$SURFSKY_API_BASE_URL/profiles/PROFILE_UUID/start" \
      -H "X-Cloud-Api-Token: $SURFSKY_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{}'
    ```
  </Tab>
</Tabs>

Response:

```json theme={null}
{
  "success": true,
  "internal_uuid": "a8fb62f90611456aa75422b01c385a62",
  "ws_url": "wss://YOUR_API_HOST/proxy/a8fb62f90611456aa75422b01c385a62"
}
```

### 2. Connect

Pass the returned `ws_url` to your framework's CDP connection method. Use the existing browser context to work with the profile's state.

The default inactivity timeout is 30 seconds. To allow more time, set `inactive_kill_timeout` in the start request. For example, `"browser_settings": {"inactive_kill_timeout": 300}` allows 300 seconds of inactivity.

To interact with the browser through HTTP requests, use the [Scraping API](/quickstart/scraping_api) with the returned `internal_uuid`.

### 3. Stop it

<Info>A running browser occupies 1 browser slot until it stops.</Info>

You can stop the browser in 3 ways:

* Call a method that closes the remote browser, such as Puppeteer's `browser.close()`.
* Leave it idle until `inactive_kill_timeout` expires.
* Send the stop request below.

Replace `INTERNAL_UUID` with the value from your start response:

```bash theme={null}
curl --fail-with-body -X POST \
  "$SURFSKY_API_BASE_URL/profiles/INTERNAL_UUID/stop" \
  -H "X-Cloud-Api-Token: $SURFSKY_API_TOKEN"
```

<Warning>
  Playwright's `browser.close()` over CDP only disconnects. Use the stop request or
  [close it through CDP](/quickstart/playwright#stop-the-session)
  to end the session immediately.
</Warning>

<span id="next" />

## If the example fails

| Error                                        | Check                                                                        |
| -------------------------------------------- | ---------------------------------------------------------------------------- |
| `not_authorized`                             | The token is set and has no leading or trailing whitespace.                  |
| `namespace_not_allowed`                      | The base URL matches the one assigned to your account.                       |
| `proxy_required` or `proxy_pool_unavailable` | Your account has a proxy pool, or the start request supplies your own proxy. |
| `parallel_browsers_limit_reached`            | An existing browser must stop before another can start.                      |

See [Errors](/errors) for other API failures. Continue with [Sessions](/sessions) to reuse browser state, or the [Python](/sdk/python) and [TypeScript](/sdk/typescript) SDK guides for browser actions and pooling.
