Web Only: RTC Mode is currently available for Web applications only.
Do not call initializeAudioContext() — it is not needed in RTC Mode. Avatar audio is delivered as a native WebRTC audio track by the Agora client SDK, not through the AvatarKit SDK’s internal audio player. The AvatarPlayer adapter only feeds animation data to the SDK for rendering; audio playback is handled entirely by Agora’s WebRTC stack.
Installation
pnpm add @spatialwalk/avatarkit @spatialwalk/avatarkit-rtc agora-rtc-sdk-ng
npm install @spatialwalk/avatarkit @spatialwalk/avatarkit-rtc agora-rtc-sdk-ng
yarn add @spatialwalk/avatarkit @spatialwalk/avatarkit-rtc agora-rtc-sdk-ng
You also need to configure your build tool for WASM files — see Build Tool Configuration.
Authentication
| Credential | How to Obtain | Notes |
|---|
| App ID | Developer Platform → Create App | For SDK initialization |
| Session Token | Your backend → AvatarKit Server | For avatar loading (max 1 hour) |
| Agora App ID | Agora Console | For RTC connection |
| Agora Token | Your backend → Agora Server | Required in production |
Quick Start
Initialize SDK in Host Mode
import { AvatarSDK, AvatarManager, AvatarView, DrivingServiceMode, Environment } from '@spatialwalk/avatarkit'
await AvatarSDK.initialize('your-app-id', {
environment: Environment.intl,
drivingServiceMode: DrivingServiceMode.host, // MUST be host for RTC
})
AvatarSDK.setSessionToken('your-session-token')
Load Avatar & Create View
const avatar = await AvatarManager.shared.load('avatar-id')
const container = document.getElementById('avatar-container')!
const avatarView = new AvatarView(avatar, container)
Create Player with Agora Provider
import { AvatarPlayer, AgoraProvider } from '@spatialwalk/avatarkit-rtc'
const provider = new AgoraProvider({
debugLogging: true, // Optional: enable verbose debug logs
})
const player = new AvatarPlayer(provider, avatarView, {
logLevel: 'warning',
})
Connect to Agora
await player.connect({
appId: 'your-agora-app-id',
channel: 'channel-name',
token: 'your-agora-token', // Required in production
uid: 0, // 0 = auto assign
})
Start Voice Interaction
// Start microphone publishing
await player.startPublishing()
// Stop microphone
await player.stopPublishing()
// Disconnect when done
await player.disconnect()
AgoraProvider Options
const provider = new AgoraProvider(options?: AgoraProviderOptions)
interface AgoraProviderOptions {
/** Enable verbose debug logging, default false */
debugLogging?: boolean
}
AvatarPlayer API
Constructor
new AvatarPlayer(provider: AgoraProvider, avatarView: AvatarView, options?: AvatarPlayerOptions)
AvatarPlayerOptions
interface AvatarPlayerOptions {
/** Start speaking transition frames, default 5 (~200ms at 25fps) */
transitionStartFrameCount?: number
/** End speaking transition frames, default 40 (~1600ms at 25fps) */
transitionEndFrameCount?: number
/** Log level: 'info' | 'warning' | 'error' | 'none', default 'warning' */
logLevel?: LogLevel
}
Connection
// Connect to Agora
await player.connect(config: AgoraConnectionConfig)
// Disconnect and clean up
await player.disconnect()
// Reconnect using last config (useful after stalls)
await player.reconnect()
// Check connection status
player.isConnected // boolean
player.getConnectionState() // ConnectionState
AgoraConnectionConfig
interface AgoraConnectionConfig {
appId: string // Agora App ID
channel: string // Channel name
token?: string // Auth token (required in production)
uid?: number // User ID (0 = auto assign)
}
Microphone Control
// Start microphone (requests permission automatically)
await player.startPublishing()
// Stop microphone
await player.stopPublishing()
Custom Audio Publishing
For non-microphone audio sources.
// Publish a custom audio track
await player.publishAudio(track: MediaStreamTrack)
// Stop custom audio
await player.unpublishAudio()
unpublishAudio() does not stop the track. You are responsible for calling track.stop() to release the resource.
Native Client Access
Access the underlying Agora client for advanced features.
import { AgoraClient } from '@spatialwalk/avatarkit-rtc'
// Via provider (recommended — full type safety)
const client = provider.getNativeClient() // AgoraClient | null
// Via player (requires type assertion)
const client = player.getNativeClient() as AgoraClient | null
console.log('Connection state:', client?.connectionState)
ConnectionState
type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'failed'
Events
player.on(event: string, handler: Function)
player.off(event: string, handler: Function)
| Event | Callback | Description |
|---|
'connected' | () | Connected to Agora |
'disconnected' | () | Disconnected from Agora |
'error' | (error: Error) | An error occurred |
'connection-state-changed' | (state: ConnectionState) | Connection state changed |
'stalled' | () | Data stream stalled (no frames for 3s) |
When a stalled event fires, the avatar automatically transitions to idle animation. Consider calling player.reconnect() to recover.
Complete Example
import { AvatarPlayer, AgoraProvider } from '@spatialwalk/avatarkit-rtc'
import { AvatarSDK, AvatarView, AvatarManager, DrivingServiceMode, Environment } from '@spatialwalk/avatarkit'
async function init() {
// Initialize SDK in host mode
await AvatarSDK.initialize('your-app-id', {
environment: Environment.intl,
drivingServiceMode: DrivingServiceMode.host,
})
AvatarSDK.setSessionToken('your-session-token')
// Load avatar and create view
const avatar = await AvatarManager.shared.load('character-id')
const container = document.getElementById('avatar-container')!
const avatarView = new AvatarView(avatar, container)
// Create player with Agora provider
const provider = new AgoraProvider({ debugLogging: true })
const player = new AvatarPlayer(provider, avatarView, {
logLevel: 'info',
})
// Listen to events
player.on('connected', () => console.log('Connected!'))
player.on('disconnected', () => console.log('Disconnected!'))
player.on('error', (err) => console.error('Error:', err))
player.on('stalled', async () => {
console.log('Stream stalled, reconnecting...')
await player.reconnect()
})
// Connect to Agora
await player.connect({
appId: 'your-agora-app-id',
channel: 'my-channel',
token: 'your-agora-token',
uid: 0,
})
// Start microphone
await player.startPublishing()
}
Browser Compatibility
| Browser | Minimum Version | Notes |
|---|
| Chrome | 74+ | H.264 + SEI |
| Firefox | 78+ | H.264 + SEI |
| Safari | 14.1+ | H.264 + SEI |
| Edge | 79+ | Same as Chrome |