Build your first multi-character session
Put two or more Convai characters in one Unity scene, connect them as a single shared room, and confirm that the room becomes ready for input.
Build a scene in which two Convai characters share one room, connect it from a script, and confirm that both memberships appear in the roster. This page assumes you already have a working single-character scene and want to add a second character to it.
Adding a second ConvaiCharacter changes how the whole scene connects. With one registered character the SDK connects a single-character room; with two or more it sends a roster and the session gains a membership layer. Existing code that resolves messages by character ID needs the review described in Character identity and addressing.
Prerequisites
A Unity scene that already contains
ConvaiManager,ConvaiRoomManager, andConvaiPlayer. See Build a custom scene if you are starting from an empty scene.A configured API key. See Configure the API key.
Two Character IDs from your Convai dashboard.
Set up the scene
Add a second character
Add a second GameObject with a ConvaiCharacter component, alongside the one your scene already has. Give each component a distinct Character Name so transcripts and logs stay readable.
Both components register themselves with the manager when the scene loads, which is what makes the room a multi-character room at connect.
Give every character a Character ID
Set the Character ID field on both ConvaiCharacter components. A character with an empty ID fails the roster validation, and the connect attempt is rejected before any request is sent.
Two characters may use the same Character ID — that creates two independently addressable instances of one character. Give them different IDs for this walkthrough so each roster entry is distinguishable in the Console.
Add the bootstrap script
Create the script below, add it to any GameObject in the scene, and assign one of your characters to the Initial Character field.
The assignment matters. The SDK infers a conversation target automatically only when the scene owns exactly one character, so a scene with two characters must name the target. That character is placed first in the roster and becomes the room's initial character.
Connect and wait for the room
ConnectAsync faults with a ConvaiOperationException when the roster is rejected or the connection fails, and its Code property carries the session error code. WaitUntilReadyAsync faults with an InvalidOperationException when the initial character fails to start, carrying the message Initial character failed to start (<code>).. Handle both — an unhandled fault in an async void method is silently swallowed by Unity.
using System;
using System.Threading;
using Convai.Runtime.Components;
using Convai.Runtime.Core.Async;
using Convai.Runtime.Room;
using UnityEngine;
public class MultiCharacterSessionBootstrap : MonoBehaviour
{
[SerializeField] private ConvaiCharacter _initialCharacter;
private readonly CancellationTokenSource _lifetime = new();
private async void Start()
{
ConvaiManager manager = ConvaiManager.ActiveManager;
if (manager == null || _initialCharacter == null)
{
Debug.LogError("[MultiCharacter] Assign an initial character and add a ConvaiManager to the scene.");
return;
}
manager.SetExplicitConversationTarget(_initialCharacter);
try
{
await manager.ConnectAsync(_lifetime.Token);
}
catch (ConvaiOperationException error)
{
Debug.LogError($"[MultiCharacter] Connect failed ({error.Code}): {error.Message}");
return;
}
catch (OperationCanceledException)
{
return;
}
if (!manager.TryGetRoomConnectionService(out IConvaiRoomConnectionService roomService))
return;
MultiCharacterRoomSession session = roomService.CurrentMultiCharacterSession;
if (session == null)
{
Debug.LogWarning("[MultiCharacter] Connected as a single-character room. Check that both characters are registered.");
return;
}
try
{
await session.WaitUntilReadyAsync(_lifetime.Token);
}
catch (InvalidOperationException error)
{
Debug.LogError($"[MultiCharacter] {error.Message}");
return;
}
catch (OperationCanceledException)
{
return;
}
foreach (CharacterRoomMembership membership in session.Characters)
Debug.Log(
$"[MultiCharacter] {membership.CharacterId} membership {membership.MembershipId} " +
$"is {membership.Status} (initial: {membership.IsInitial})");
}
private void OnDestroy()
{
_lifetime.Cancel();
_lifetime.Dispose();
}
}Verify the room
Confirm all four of the following in the Console before you build anything on top of the room.
CurrentMultiCharacterSessionis notnull, which the script reports by not logging the single-character warning.session.Charactersholds one membership perConvaiCharacterin the scene.Exactly one membership logs
initial: True, and it is the character you assigned.Every membership has a distinct
MembershipId.
Speaking to the room now reaches the initial character. Routing input to any other membership is a separate step; the room stays on the initial character until you change the interaction target.
Troubleshooting
The Console reports a line beginning [ConvaiRoomManager] Room ownership did not resolve an active conversation target.
The scene owns two or more characters and none was named as the target.
Call SetExplicitConversationTarget before connecting, as the script above does.
Connect fails with Cannot connect because no active character is available.
No active character was resolved when ConnectAsync ran — for example, every owned character is inactive or disabled.
Activate at least one ConvaiCharacter in the scene, or call SetExplicitConversationTarget with an active character, before connecting.
Connect fails with Every character in a multi-character room requires a Character ID.
One active, enabled ConvaiCharacter has an empty Character ID. An inactive character with no ID does not trigger this — it never reaches roster validation.
Set the Character ID field on every active character in the scene, and on any inactive character before you activate and add it later with AddCharacterAsync.
Connect fails with Multi-character roster contains null or duplicate character references.
The same ConvaiCharacter component was registered twice.
Register each component once. Use a second component instance to add a clone of the same character.
Connect fails with Multi-character rooms support at most 50 characters.
More than 50 active, enabled characters are registered with the manager.
Reduce the active cast to 50 or fewer before connecting.
A character is missing from session.Characters even though it is in the scene
That character's GameObject or ConvaiCharacter component was inactive or disabled when the room connected. The SDK excludes inactive characters from the startup roster without raising an error.
Activate the character before connecting, or add it after connecting with Add and remove characters at runtime.
The script logs the single-character warning
Only one character was active and enabled when the manager connected — commonly because a second ConvaiCharacter (or its GameObject) was inactive.
Confirm both GameObject instances are active in the scene before the connect call runs.
Next steps
Read Character identity and addressing before writing code that maps audio or matches events, then Roster readiness and partial dispatch to handle a character that starts slowly or fails.
Last updated
Was this helpful?