# Quickstart — Live

Create a Live instance, pass a server-issued ticket, connect, and clean up.

Canonical: https://developer.realsee.ai/docs/live/quickstart
Source: https://developer.realsee.ai/docs/live/quickstart.md
Language: en

This quickstart assumes your backend can return a Live WebSocket URL and ticket. Keep App credentials server-side; the browser should receive only the Live entrance URL, ticket, and optional voice sign data required for the current room.

## 1. Install

```bash
npm install @realsee/live@0.7.6 react@18 trtc-js-sdk amazon-chime-sdk-js @realsee/jsbridge-x
```

The browser-only co-viewing path can start with `@realsee/live@0.7.6` and `react@18`. Add `trtc-js-sdk`, `amazon-chime-sdk-js`, or `@realsee/jsbridge-x` when you use the built-in RTC implementations.

## 2. Create the instance

The generic form is `createLive<MyKeyframes>`. The generic maps each keyframe channel to the serializable state shape your app will synchronize.

```ts
import { createLive, LiveState } from '@realsee/live'

interface MyKeyframes {
  FiveState: unknown
  activePoi: { id: string; title: string } | null
}

const live = createLive<MyKeyframes>({
  getTicket: async () => {
    const response = await fetch('/api/live/ticket')
    const payload = await response.json()
    return payload.ticket
  },
  __debug__: import.meta.env.DEV,
})

live.on('stateChange', (state, prevState) => {
  console.log({ state, prevState })
})

await live.connect({
  url: 'wss://ws-access.realsee.com/.../room',
  force: true,
})

if (live.state === LiveState.OPEN) {
  live.sendKeyframe('activePoi', null)
}
```

`live.connect(options?)` accepts `url`, `force`, `getTicket`, and `rtcMicStatus`. The package also supports passing `url` and `getTicket` to `createLive`; when both are present the instance can auto-connect.

## 3. React integration

Use `createLiveReact<MyKeyframes>` when your controls are React components. It creates a `LiveProvider`, action hooks, keyframe hooks, and state hooks around one Live instance.

```tsx
import { createLiveReact } from '@realsee/live'

interface MyKeyframes {
  FiveState: unknown
  activePoi: { id: string; title: string } | null
}

export const LiveReact = createLiveReact<MyKeyframes>({
  getTicket: async () => {
    const response = await fetch('/api/live/ticket')
    return response.json().then((payload) => payload.ticket)
  },
})

export function LiveRoot({ children }: { children: React.ReactNode }) {
  return <LiveReact.LiveProvider>{children}</LiveReact.LiveProvider>
}

export function ConnectButton({ wsUrl }: { wsUrl: string }) {
  const { connect } = LiveReact.useLiveAction()

  return (
    <button onClick={() => connect({ url: wsUrl, force: true })}>
      Join live room
    </button>
  )
}
```

## 4. Clean up

Call `live.exit()` when the current user leaves the room. Call `live.close()` when the room owner closes the room for everyone. Call `live.dispose()` when the page or React tree is unmounted and the instance should not be reused.

```ts
window.addEventListener('beforeunload', () => {
  void live.dispose()
})
```

## Backend boundary

Ticket and voice sign endpoints must be same-origin endpoints in your app:

- `GET /api/live/ticket` returns the ticket used by `getTicket`.
- `POST /api/live/voice-sign` returns the voice sign used by `getVoiceSign`.
- OpenAPI app keys and app secrets stay on the server.

See [OpenAPI](https://developer.realsee.ai/docs/open-api) for the credential model and [Team app management](https://developer.realsee.ai/docs/team-app-management) for trial-app creation and the permanent Completed + AK binding.
