@scenaro/sdk separates a portable session contract from the Transport that carries
it — see Transport for the full picture. For the majority of
integrations — a voice button embedded on a page — the quickstart
is all you need, and you’ll never see an engine-specific type. This guide is for the minority
of integrations that need more: custom audio visualizers, avatars, multi-participant layouts,
or anything else the current engine’s ecosystem already does well.
This is an assumed extension point, not an escape hatch you’re forced into. Scenaro doesn’t
wrap or re-export the engine’s components — you import them directly from their own packages
and use them next to
useScenaroSession.1. When to use this guide
Reach for Transport extensions when you need:- Custom audio visualizers or waveforms
- Agent avatars driven by speaking state
- Multi-participant layouts
- Anything else already solved by the current engine’s component library
status, messages, config, or tool calls, stay on the portable contract —
you don’t need anything in this guide.
2. Portable contract vs engine extension
useScenaroSession always returns the same portable contract (status, agentState,
messages, config, tools, events) regardless of which Transport implementation is running
underneath. On top of that, it also exposes room — an engine extension: the live engine
handle for the current Transport implementation.
| Contract | Stability | Where it’s documented |
|---|---|---|
status, agentState, messages, config, tools, events | Portable — stable across future Transport implementations | Quickstart, SDK reference |
room, RoomContext, @livekit/components-react hooks/components | Engine-specific (LiveKit today) — not guaranteed to carry over to a future Transport implementation | This guide |
status or agentState keeps working if Scenaro ever adds another Transport
implementation (e.g. Pipecat) behind useScenaroSession. Code that calls
room.localParticipant... or uses useVoiceAssistant() is written against the current engine
directly — the same trade-off you’d make using that engine standalone. See
Transport for the internal boundary that makes this possible.
3. LiveKit implementation (today)
The current Transport implementation is LiveKit. This section is the concrete, engine-specific how-to.Install the LiveKit peer dependencies
livekit-client and @livekit/components-react are peer dependencies of @scenaro/sdk —
install them once you start using this guide (the quickstart does
not require them):
Using room with LiveKit components
ScenaroProvider injects RoomContext for you, so LiveKit’s components and hooks work as soon
as a session is active — no manual <RoomContext.Provider> wiring required.
What stays yours to maintain
Because this code is written against LiveKit’s API surface directly, keep in mind:- A future engine swap isn’t automatic here. If Scenaro adds a Pipecat Transport
implementation behind
useScenaroSessionin the future, the portable contract will keep working unchanged. Code that callsroom.*or LiveKit component hooks will need to be ported by hand — the same way any code written against a specific vendor’s low-level API would. - Support boundary. Scenaro’s contract covers session, auth, config, tools, and features.
Anything under
room— audio devices, track subscriptions, participant behavior — is LiveKit’s surface; consult the LiveKit docs for it. - Don’t mix contracts in shared components. Keep components that only need the portable contract free of LiveKit imports, so they stay reusable if the Transport implementation ever changes.
Next steps
- Transport — the engine-agnostic boundary behind this guide
- SDK reference — React — full
useScenaroSessionandScenaroSessionAPI - LiveKit Components React docs — hooks and components available on
room