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

> ## Agent Instructions
> These docs cover learner integrations through Hosted Lab Pages, the SDK, and the REST API. Content management is outside this integration scope.
> Read the setup page for the chosen approach before implementing it. Keep organization API keys and hosted mint secrets on the server.
> The public SDK is coming soon. Check the SDK quickstart for current availability. Do not invent installation commands or direct readers to a private package.
> Cybr provides completion tracking and CTF verification. The integrating platform decides whether to award points.

# Browser terminals

> Create a terminal session on the server and connect from your browser interface.

The terminal uses a persistent WebSocket connection. The server SDK creates temporary credentials. The browser helper handles the connection protocol.

## Check availability

Web terminals currently support AWS labs only. Show the terminal action for labs with `provider: 'aws'` and `webTerminal: true`.

The environment must also be ready. If an Azure lab enables its terminal indicator, session creation still returns `TERMINAL_NOT_SUPPORTED`.

The server can still reject a session because the lab ended or the terminal service is unavailable. A content indicator is not authorization.

## Create a session on the server

1. Resolve the current learner session.
2. Check that the deployment belongs to that session.
3. Create temporary credentials:

```ts theme={null}
const session = await cybr.deployments.createTerminalSession(deploymentId)
```

4. Return `session` to that learner with `Cache-Control: no-store`.

The result contains `wsUrl`, `protocols`, and `expiresAt`. It contains no organization API key.

The SDK retries `CONTAINER_STARTING` every two seconds, for up to 30 seconds. Other terminal failures do not use that startup loop.

## Connect the browser

`getSession()` represents a request to your own server integration. Its route and session checks belong to your application.

```ts theme={null}
import { createTerminalClient } from '@cybr/labs-sdk/terminal'

const terminal = createTerminalClient({
  getSession,
  onOutput: (bytes) => screen.write(bytes),
  onStateChange: (state) => showConnectionState(state),
  onExit: (code) => showExit(code),
  onError: (error) => showConnectionError(error.message)
})

terminal.resize(80, 24)
try {
  await terminal.connect()
} catch {
  // onError reports connection failures. Disposal can also reject this promise.
}
```

`screen`, `showConnectionState`, `showExit`, and `showConnectionError` represent your UI code. The helper does not require a framework or terminal renderer.

The [browser helper reference](/reference/terminal) includes an xterm example and all callback types.

## Input and resize

After readiness, send keyboard input with `write()`:

```ts theme={null}
terminal.write('pwd\r')
terminal.resize(100, 30)
```

The helper sends binary UTF-8 input. It delivers binary output as `Uint8Array` values.

## Reconnect and close

When the learner requests a reconnect, call `reconnect()`:

```ts theme={null}
try {
  await terminal.reconnect()
} catch {
  // onError reports connection failures. Replacement or disposal can also reject.
}
```

Every connection requests fresh credentials. The helper does not reconnect automatically or replay previous input.

Both connection methods return promises that can reject. An `onError` callback does not handle those promise rejections.

Use `onStateChange` to handle a closed connection. After readiness, an ordinary socket close reports `closed` without calling `onError`.

When your terminal view closes, call `dispose()`:

```ts theme={null}
terminal.dispose()
```

Disposal closes the socket and removes listeners. It does not end the deployment. The separate end action calls `deployment.destroy()`.

## Expiration and errors

`expiresAt` is the deadline for connection authorization. It is not the shell lifetime or deployment deadline.

An existing connection can continue after token expiration until the lab ends. A reconnect requires fresh credentials.

An ended lab cannot create a new terminal session. A reconnect can also fail because terminal support is disabled or the service is unavailable.

Show these failures in the terminal view. A new lab launch requires a separate learner action.

The [WebSocket protocol](/api-reference/terminal-protocol) documents the wire format for direct clients.
