Skip to main content
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.
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

Connection

Creates an Uplink session using your project credentials.
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() to connect. Example:
const session = await uplink.session('<project-api-key>', {
  restrict: { verifier: '<your-own-secret>' }
})
Uplink never stores your verifier. That means you must reuse the same secret on later calls (for example, with uplink.getSession()) without re-fetching it from Uplink.
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.
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().
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.
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.
Example:
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 })
Returns 404 if the session does not exist or does not belong to the API key’s project.
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.
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 type below. Example:
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)
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.
Creates a client from an Uplink session.
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:
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:
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
Connects directly to an Uplink session via WebSocket URL. This is an alternative to using uplink.session() + fromSession().
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:
import uplink from '@uplink-code/uplink'

const client = await uplink.client.connect(
  'wss://relay.uplink.build/session/<jwt>'
)
console.log('Connected to Uplink')
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.

Browser operations

client.launch()

Launches a new browser on a worker. If no worker address is provided, uses the first available worker.
client.launch(address?: Address): Promise<Browser>
Parameters:
  • address (optional): Worker address to launch browser on
Returns: Promise<Browser> - New browser instance Example:
// 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.
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:
// 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.
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:
// 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.
client.workers(): ClientWorker[]
Returns: ClientWorker[] - Array of connected workers Example:
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.
client.terminate(address?: Address): Promise<void>
Parameters:
  • address (optional): Worker address to terminate. If not provided, terminates first available worker.
Returns: Promise<void> Example:
// Terminate first available worker
await client.terminate()

// Terminate specific worker
await client.terminate(worker.address)
Terminating a worker closes all browsers running on that worker and disconnects the device from the session.

Connection management

client.close()

Closes the client connection and cleans up resources.
client.close(): Promise<void>
Returns: Promise<void> Example:
await client.close()
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.

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).
client.on(event: 'worker-connected', handler: (worker: ClientWorker) => void)
Example:
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).
client.on(event: 'worker-disconnected', handler: (worker: ClientWorker) => void)
Example:
client.on('worker-disconnected', (worker) => {
  console.log('Worker disconnected:', worker.address)
})

Types

ClientOptions

interface ClientOptions {
  agent?: Agent  // Optional AI agent from @uplink-code/ai
}

Address

Worker identifier - a hex-encoded address:
type Address = string  // Hex-encoded worker address

SessionDetails

Returned by uplink.sessionDetails(). Aggregates session-level metadata across the API, devices, billing, and tags.
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

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)

ClientWorker

Device-specific operations

Browser

Browser management

Core concepts

Architecture overview

Sessions

Session management