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

# Client

> API reference for the Uplink Client class

The `Client` class is your main entry point for Uplink automation. It manages the WebSocket connection to the Uplink relay server and provides methods for worker and browser management.

<Info>
  **Key concepts:**

  * **Device**: A physical iOS or Android device
  * **Worker**: A worker created using the native Uplink SDK (a device can create multiple workers)
  * **Address**: A hex-encoded identifier for workers
</Info>

## Connection

### `uplink.session()`

Creates an Uplink session using your project credentials.

```typescript theme={null}
uplink.session(
  apiKey: string,
  options?: SessionOptions
): Promise<Session>
```

**Parameters:**

* `apiKey`: Your project API key from Uplink Console. The session is automatically scoped to the project this key belongs to.
* `options` (optional): Session configuration
  * `include`: Cryptographic key options
    * `ecdsa`: Boolean, include ECDSA keys (default: false)
    * `ecdh`: Boolean, include ECDH keys (default: false)
  * `restrict`: `{ verifier: string }` — a secret value you choose to keep the session secure. Only your code knows this value; anyone trying to use the session without it will be rejected. **Recommended for any production use.**

**Returns:** `Promise<Session>` - Session object with the shape `{ sessionId, sessionUrl, qrUrl, credential?, keys? }`. Pass it directly to [`uplink.client.fromSession()`](#uplinkclientfromsession) to connect.

**Example:**

```typescript theme={null}
const session = await uplink.session('<project-api-key>', {
  restrict: { verifier: '<your-own-secret>' }
})
```

<Note>
  Uplink never stores your verifier. That means you must reuse the same secret on later calls (for example, with [`uplink.getSession()`](#uplinkgetsession)) without re-fetching it from Uplink.
</Note>

### `uplink.getSession()`

Looks up an existing session by ID and returns the same `Session` shape that `uplink.session()` returns — including a fresh `sessionUrl`. Useful when you already have a `sessionId` (for example, persisted across runs) and want to keep using the original session instead of creating a new one, or recover the keys that were generated when it was created.

```typescript theme={null}
uplink.getSession(
  apiKey: string,
  sessionId: string,
  options?: GetSessionOptions
): Promise<Session>
```

**Parameters:**

* `apiKey`: Your project API key from Uplink Console
* `sessionId`: The ID of an existing session belonging to the API key's project
* `options` (optional):
  * `include`: Cryptographic key options
    * `ecdsa`: Boolean, include the project ECDSA key pair (default: false)
    * `ecdh`: Boolean, include the session ECDH key pair if one was created at session-create time (default: false)

**Returns:** `Promise<Session>` - Same shape as `uplink.session()`, but without a `credential` field. If the session was created with a `restrict.verifier`, merge the same secret back in before passing the session to `fromSession()`.

<Note>
  You only need to worry about merging `credential` when you're picking a session up later through `getSession()`. If you call `fromSession()` directly with the object returned by `uplink.session()`, the credential is already attached for you.
</Note>

<Note>
  The `include.ecdh` / `include.ecdsa` flags only re-export keys that **Uplink generated** for the session. If you brought your own key pair instead, `getSession()` won't return anything in `keys` — you're expected to re-attach your own.
</Note>

**Example:**

```typescript theme={null}
import uplink from '@uplink-code/uplink'

const credential = '<your-own-secret>'  // the same verifier you used when creating the session

const session = await uplink.getSession(
  '<project-api-key>',
  '<existing-session-id>',
  { include: { ecdsa: true, ecdh: true } }
)

const client = await uplink.client.fromSession({ ...session, credential })
```

<Note>
  Returns `404` if the session does not exist or does not belong to the API key's project.
</Note>

### `uplink.sessionDetails()`

Fetches a richer view of an existing session for display in dashboards or admin views — including paired devices, total bytes streamed, total connection duration, tags, and the parent project and organization. Use this when you need to inspect a session, not to reconnect to it.

```typescript theme={null}
uplink.sessionDetails(
  apiKey: string,
  sessionId: string,
  options?: { host?: string }
): Promise<SessionDetails>
```

**Parameters:**

* `apiKey`: Your project API key from Uplink Console
* `sessionId`: The ID of an existing session belonging to the API key's project

**Returns:** `Promise<SessionDetails>` - Session metadata. See the [SessionDetails](#sessiondetails) type below.

**Example:**

```typescript theme={null}
import uplink from '@uplink-code/uplink'

const details = await uplink.sessionDetails(
  '<project-api-key>',
  '<existing-session-id>'
)
console.log('Devices paired:', details.devices.length)
console.log('Bytes streamed:', details.total_bytes)
console.log('Connection time (s):', details.total_connection_duration)
```

<Tip>
  **When to reach for which method:**

  * `uplink.session()` — create a brand-new session.
  * `uplink.getSession()` — refetch an existing session in the same shape as `session()` so you can pass it to `fromSession()`.
  * `uplink.sessionDetails()` — inspect a session's metadata (devices, usage, tags). Not for reconnecting.
</Tip>

### `uplink.client.fromSession()`

Creates a client from an Uplink session.

```typescript theme={null}
uplink.client.fromSession(
  session: Session,
  options?: ClientOptions
): Promise<Client>
```

**Parameters:**

* `session`: Session object created with `uplink.session()`
* `options` (optional): Connection options
  * `agent`: Optional AI agent for natural language automation (requires `@uplink-code/ai`)

**Returns:** `Promise<Client>` - Connected client instance

**Complete example:**

```typescript theme={null}
import uplink from '@uplink-code/uplink'

const session = await uplink.session('<project-api-key>', {
  include: { ecdsa: true, ecdh: true }
})
const client = await uplink.client.fromSession(session)
console.log('Connected to Uplink')
```

**With AI agent:**

```typescript theme={null}
import uplink from '@uplink-code/uplink'
import ai from '@uplink-code/ai'

const agent = ai.createAgent({
  provider: 'anthropic',
  options: {
    apiKey: process.env.ANTHROPIC_API_KEY
  }
})

const session = await uplink.session('<project-api-key>', {
  include: { ecdsa: true, ecdh: true }
})
const client = await uplink.client.fromSession(session, { agent })

// All pages created from this client will have AI capabilities
const browser = await client.launch()
const page = await browser.newPage()

await page.goto('https://example.com')
await page.act('Click the sign in button') // AI-powered action
```

### `uplink.client.connect()` (Alternative)

Connects directly to an Uplink session via WebSocket URL. This is an alternative to using `uplink.session()` + `fromSession()`.

```typescript theme={null}
uplink.client.connect(
  url: string | URL,
  options?: ClientOptions
): Promise<Client>
```

**Parameters:**

* `url`: WebSocket URL in the format `wss://relay.uplink.build/session/<jwt>`
* `options` (optional): Connection options
  * `agent`: Optional AI agent for natural language automation (requires `@uplink-code/ai`)

**Returns:** `Promise<Client>` - Connected client instance

**Example:**

```typescript theme={null}
import uplink from '@uplink-code/uplink'

const client = await uplink.client.connect(
  'wss://relay.uplink.build/session/<jwt>'
)
console.log('Connected to Uplink')
```

<Note>
  **Recommended approach**: Use `uplink.session()` + `fromSession()` for better credential management and project organization. Use `connect()` when you need to work with pre-generated session URLs.
</Note>

## Browser operations

### `client.launch()`

Launches a new browser on a worker. If no worker address is provided, uses the first available worker.

```typescript theme={null}
client.launch(address?: Address): Promise<Browser>
```

**Parameters:**

* `address` (optional): Worker address to launch browser on

**Returns:** `Promise<Browser>` - New browser instance

**Example:**

```typescript theme={null}
// Launch on first available worker
const browser = await client.launch()

// Launch on specific worker using its address
const workers = await client.workers()
const browser = await client.launch(workers[0].address)
```

### `client.connect()`

Connects to an existing browser by its handle.

```typescript theme={null}
client.connect(handle: string, address?: Address): Promise<Browser>
```

**Parameters:**

* `handle`: Browser handle identifier
* `address` (optional): Worker address where browser is running

**Returns:** `Promise<Browser>` - Connected browser instance

**Example:**

```typescript theme={null}
// Connect to browser by handle (searches all workers)
const workers = await client.workers()
const browsers = await workers[0].browsers()

const existingBrowser = await client.connect(browsers[0].handle)
const page = await existingBrowser.newPage()
```

### `client.browsers()`

Lists all browsers on a worker.

```typescript theme={null}
client.browsers(address?: Address): Promise<Browser[]>
```

**Parameters:**

* `address` (optional): Worker address to query. If not provided, queries first available worker.

**Returns:** `Promise<Browser[]>` - Array of browser instances

**Example:**

```typescript theme={null}
// List browsers on first available worker
const browsers = await client.browsers()
console.log(`${browsers.length} browsers running`)

for (const browser of browsers) {
  console.log('Browser:', browser.handle)
}
```

## Worker operations

### `client.workers()`

Returns list of currently connected workers.

```typescript theme={null}
client.workers(): ClientWorker[]
```

**Returns:** `ClientWorker[]` - Array of connected workers

**Example:**

```typescript theme={null}
const workers = client.workers()

console.log(`${workers.length} workers connected`)
workers.forEach(worker => {
  console.log('Worker address:', worker.address)
})
```

### `client.terminate()`

Terminates a worker connection.

```typescript theme={null}
client.terminate(address?: Address): Promise<void>
```

**Parameters:**

* `address` (optional): Worker address to terminate. If not provided, terminates first available worker.

**Returns:** `Promise<void>`

**Example:**

```typescript theme={null}
// Terminate first available worker
await client.terminate()

// Terminate specific worker
await client.terminate(worker.address)
```

<Warning>
  Terminating a worker closes all browsers running on that worker and disconnects the device from the session.
</Warning>

## Connection management

### `client.close()`

Closes the client connection and cleans up resources.

```typescript theme={null}
client.close(): Promise<void>
```

**Returns:** `Promise<void>`

**Example:**

```typescript theme={null}
await client.close()
```

<Tip>
  Always call `close()` when done to properly clean up WebSocket connections and resources. Connection time is determined by how long clients and workers are connected to a session.
</Tip>

## Events

The client emits events for worker connection lifecycle.

### `worker-connected`

Emitted when a new worker connects to the session (i.e., when a device running the Uplink SDK joins).

```typescript theme={null}
client.on(event: 'worker-connected', handler: (worker: ClientWorker) => void)
```

**Example:**

```typescript theme={null}
client.on('worker-connected', (worker) => {
  console.log('Worker connected:', worker.address)
})
```

### `worker-disconnected`

Emitted when a worker disconnects from the session (i.e., when a device leaves or loses connection).

```typescript theme={null}
client.on(event: 'worker-disconnected', handler: (worker: ClientWorker) => void)
```

**Example:**

```typescript theme={null}
client.on('worker-disconnected', (worker) => {
  console.log('Worker disconnected:', worker.address)
})
```

## Types

### ClientOptions

```typescript theme={null}
interface ClientOptions {
  agent?: Agent  // Optional AI agent from @uplink-code/ai
}
```

### Address

Worker identifier - a hex-encoded address:

```typescript theme={null}
type Address = string  // Hex-encoded worker address
```

### SessionDetails

Returned by `uplink.sessionDetails()`. Aggregates session-level metadata across the API, devices, billing, and tags.

```typescript theme={null}
interface SessionDetails {
  id: string
  project: {
    id: string
    name: string
    description: string | null
  }
  organization: {
    id: string
    name: string
    avatar_url: string | null
  }
  created_at: Date
  updated_at: Date
  devices: Array<{
    id: string
    device_id: string
    device_type: string
    device_model: string | null
    platform: string | null
    platform_version: string | null
  }>
  total_bytes: number
  total_connection_duration: number  // seconds
  tags: Record<string, string>
  sessionUrl: string
}
```

## Complete example

```typescript theme={null}
import uplink from '@uplink-code/uplink'

async function main() {
  // Connect to session that will be used for multiple workers doing the same script
  const session = await uplink.session('<project-api-key>', {
    include: { ecdsa: true, ecdh: true }
  })
  const client = await uplink.client.fromSession(session)

  // Listen for worker events
  client.on('worker-connected', async (worker) => {
    console.log('Worker joined:', worker.address)

    const browser = await worker.launch()
    const page = await browser.newPage()
    await page.goto('https://example.com')

    await page.close()
    await browser.close()
    await client.close()
  })

  client.on('worker-disconnected', (worker) => {
    console.log('Worker left:', worker.address)
  })
}

main().catch(console.error)
```

## Related

<CardGroup cols={2}>
  <Card title="ClientWorker" icon="mobile" href="/api-reference/client-worker">
    Device-specific operations
  </Card>

  <Card title="Browser" icon="browser" href="/api-reference/browser">
    Browser management
  </Card>

  <Card title="Core concepts" icon="book" href="/fundamentals/core-concepts">
    Architecture overview
  </Card>

  <Card title="Sessions" icon="key" href="/sessions">
    Session management
  </Card>
</CardGroup>
