> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/plugins-and-integrations/convai-unity-sdk/features/multi-character-sessions/join-an-existing-session.md).

# Join an existing room

Bring a second human participant into a Unity multi-character room another client already created, using exactly one room locator.

Bring a second human participant into a room that already exists with `JoinMultiCharacterRoomAsync`, using exactly one room locator. Use this page when a companion client needs to join a session another client already created, rather than creating a new roster.

### Prerequisites

* A multi-character session already created by another client, with its `RoomSessionId` or `SharedSessionKey` available to the joining client.
* `IConvaiRoomConnectionService`, retrieved with `ConvaiManager.TryGetRoomConnectionService`.
* A distinct `EndUserId` for the joining participant.

### Join the room

Call `JoinMultiCharacterRoomAsync(MultiCharacterJoinOptions options, CancellationToken cancellationToken = default)`. Under the hood it builds a `RoomSessionConnectOptions` with `JoinExistingMultiCharacterRoom` set, so no roster is sent — the join reuses the roster the creating client already established.

| `MultiCharacterJoinOptions` field | Use it for                                                                     |
| --------------------------------- | ------------------------------------------------------------------------------ |
| `RoomSessionId`                   | The durable room identifier returned to the creating client's `/connect` call. |
| `SharedSessionKey`                | An alternative, developer-controlled locator for the same room.                |
| `EndUserId`                       | A stable identifier for the joining participant.                               |
| `EndUserMetadata`                 | Optional key-value metadata for the joining participant.                       |
| `TurnTaking`                      | Turn-taking options for this participant's session; defaults to hands-free.    |

Set `RoomSessionId` or `SharedSessionKey`, not both — the room accepts exactly one locator per join request. Joining does not require an active character or a call to `SetInitialCharacter`; the SDK skips that requirement entirely when `JoinExistingMultiCharacterRoom` is set.

{% code title="Assets/Scripts/JoinExistingSessionBootstrap.cs" %}

```csharp
using System;
using System.Threading;
using Convai.Runtime.Core.Async;
using Convai.Runtime.Room;
using UnityEngine;

public class JoinExistingSessionBootstrap : MonoBehaviour
{
    [SerializeField] private string _roomSessionId;
    [SerializeField] private string _endUserId;

    private readonly CancellationTokenSource _lifetime = new();

    private async void Start()
    {
        ConvaiManager manager = ConvaiManager.ActiveManager;
        if (manager == null || !manager.TryGetRoomConnectionService(out IConvaiRoomConnectionService roomService))
        {
            Debug.LogError("[MultiCharacter] Add a ConvaiManager to the scene before joining a room.");
            return;
        }

        var joinOptions = new MultiCharacterJoinOptions
        {
            RoomSessionId = _roomSessionId,
            EndUserId = _endUserId
        };

        try
        {
            await roomService.JoinMultiCharacterRoomAsync(joinOptions, _lifetime.Token);
        }
        catch (ConvaiOperationException error)
        {
            Debug.LogError($"[MultiCharacter] Join failed ({error.Code}): {error.Message}");
            return;
        }
        catch (ArgumentNullException error)
        {
            Debug.LogError($"[MultiCharacter] {error.Message}");
            return;
        }
        catch (OperationCanceledException)
        {
            return;
        }

        MultiCharacterRoomSession session = roomService.CurrentMultiCharacterSession;
        if (session == null)
        {
            Debug.LogWarning("[MultiCharacter] Joined, but no multi-character session was returned.");
            return;
        }

        Debug.Log($"[MultiCharacter] Joined room {session.RoomSessionId} with {session.Characters.Count} characters.");
    }

    private void OnDestroy()
    {
        _lifetime.Cancel();
        _lifetime.Dispose();
    }
}
```

{% endcode %}

### Verify the join

Confirm both of the following in the Console before routing input from the joining client.

* `CurrentMultiCharacterSession` is not `null`, and `RoomSessionId` matches the room you intended to join.
* `session.Characters` reports the same roster the creating client sees. A membership without a local `ConvaiCharacter` bound to it is normal here — the joining scene does not need to own every character in the room.

### Troubleshooting

| Symptom                                                | Cause                                                                                        | Fix                                                                                                                                     |
| ------------------------------------------------------ | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Join fails with a `ConvaiOperationException`           | A missing or duplicate room locator, or the account cannot access the room.                  | Send exactly `RoomSessionId` or `SharedSessionKey`, not both, and confirm the value. Convai reports the reason in the exception `Code`. |
| `CurrentMultiCharacterSession` is `null` after joining | The room you joined has no roster to expose, which happens only for a single-character room. | Confirm the target room was created as a multi-character session.                                                                       |

See [Use multi-character sessions](/api-docs/api-reference/core-api-reference/live-apis-beta/multi-character-sessions.md#verify-and-troubleshoot) for the protocol-level join failure table.

### Next steps

{% content-ref url="/pages/Nb2BWKylR9bZQD6eD5vD" %}
[Conversation targeting](/api-docs/plugins-and-integrations/convai-unity-sdk/features/conversation-targeting.md)
{% endcontent-ref %}

{% content-ref url="/pages/Bh8T9RTgDy9X5ofS3Soi" %}
[Characters joining and leaving](/api-docs/plugins-and-integrations/convai-unity-sdk/features/multi-character-sessions/update-the-roster.md)
{% endcontent-ref %}

{% content-ref url="/pages/EJfmOWyLNylMlEqsZUjf" %}
[Use multi-character sessions](/api-docs/api-reference/core-api-reference/live-apis-beta/multi-character-sessions.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.convai.com/api-docs/plugins-and-integrations/convai-unity-sdk/features/multi-character-sessions/join-an-existing-session.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
