Skip to main content
Sessions are the foundation of Uplink’s security and connection model. Understanding how to create, manage, and secure sessions is essential for production use.

What is a session?

A session is an authenticated WebSocket connection that allows your JavaScript code to communicate with mobile devices. Sessions are identified by JWT tokens and enable secure, real-time bidirectional communication.
const client = await uplink.client.connect('wss://relay.uplink.build/session/<jwt>')

Creating sessions

Sessions are created through the Uplink Console and authenticated using JWT tokens.
1

Generate an API key

In your Console, navigate to SettingsAPI Keys and create a new API key. API keys are used to generate session tokens.
2

Create a session

Go to SessionsNew Session to generate a session JWT token. The token encodes the session permissions and expiration.
3

Connect using the token

Use the generated JWT in your WebSocket connection URL:
const client = await uplink.client.connect(
  'wss://relay.uplink.build/session/<your-jwt-token>'
)

Session tokens (JWT)

Session tokens are JSON Web Tokens (JWT) that contain:
  • Session ID: Unique identifier for the session
  • Permissions: What operations are allowed
  • Expiration: When the token expires
  • Scope: Which devices can connect

Token security best practices

Treat JWT tokens like passwords. Never commit them to source control or expose them in client-side code.
// ✓ Good: Use environment variables
const sessionUrl = process.env.UPLINK_SESSION_URL

// ✗ Bad: Hardcoded tokens
const sessionUrl = 'wss://relay.uplink.build/session/eyJ...'
Configure session tokens with appropriate expiration times. For automated testing, consider short-lived tokens that are regenerated for each test run.
Create tokens with only the permissions needed for the specific use case. Don’t use admin tokens for routine automation.
Regularly rotate API keys and session tokens, especially after team member changes or security incidents.

Session lifecycle

Connection

When you connect to a session, the client establishes a WebSocket connection to the Uplink relay server:
const client = await uplink.client.connect('wss://relay.uplink.build/session/<jwt>')
console.log('Connected to session')

// The client is now ready to interact with devices

Active session

During an active session:
  • Devices can connect and disconnect
  • Browsers can be launched and managed
  • Commands are sent in real-time
  • Events are emitted for device state changes
client.on('worker-connected', (device) => {
  console.log('Device joined session:', device.address)
})

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

Closing a session

Always close the client when you’re done to properly clean up resources:
// Clean up in order: pages, browsers, then client
await page.close()
await browser.close()
await client.close()

Session expiration

Sessions expire when:
  • The JWT token reaches its expiration time
  • The connection is closed by the client
  • The session is terminated in the Console
  • The API key used to create the session is revoked
When a session expires, all connected devices are disconnected and browsers are closed. Plan for graceful handling of session expiration in long-running automations.

Authentication patterns

Development

For development, you can manually create session tokens in the Console:
// .env file
UPLINK_SESSION_URL=wss://relay.uplink.build/session/eyJhbGc...

// In your code
import uplink from '@uplink-code/uplink'

const client = await uplink.client.connect(process.env.UPLINK_SESSION_URL)

Production

In production, generate session tokens programmatically using the Uplink API:
// Pseudo-code: Generate session token via API
async function createSession() {
  const response = await fetch('https://api.uplink.build/sessions', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.UPLINK_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      expiresIn: '1h',
      permissions: ['launch', 'browse']
    })
  })

  const { sessionUrl } = await response.json()
  return sessionUrl
}

const sessionUrl = await createSession()
const client = await uplink.client.connect(sessionUrl)

CI/CD integration

For automated testing in CI/CD pipelines:
# Example GitHub Actions workflow
- name: Run Uplink tests
  env:
    UPLINK_API_KEY: ${{ secrets.UPLINK_API_KEY }}
  run: |
    npm test
// In your test suite
beforeAll(async () => {
  const sessionUrl = await createUplinkSession(process.env.UPLINK_API_KEY)
  client = await uplink.client.connect(sessionUrl)
})

afterAll(async () => {
  await client.close()
})

Multi-session patterns

Isolating test runs

Create separate sessions for parallel test runs to avoid conflicts:
// Each test worker gets its own session
async function setupTestSession(workerId: string) {
  const sessionUrl = await createSession({
    label: `test-worker-${workerId}`,
    expiresIn: '1h'
  })
  return uplink.client.connect(sessionUrl)
}

Load distribution

For high-volume automation, distribute load across multiple sessions:
const sessions = await Promise.all([
  createAndConnectSession('session-1'),
  createAndConnectSession('session-2'),
  createAndConnectSession('session-3')
])

// Round-robin device allocation
const device = sessions[nextIndex++ % sessions.length]

Error handling

Handle authentication and connection errors gracefully:
try {
  const client = await uplink.client.connect(sessionUrl)
} catch (error) {
  if (error.message.includes('unauthorized')) {
    console.error('Invalid or expired session token')
  } else if (error.message.includes('connection')) {
    console.error('Failed to connect to Uplink relay')
  } else {
    console.error('Unexpected error:', error)
  }
}

Next steps