> ## Documentation Index
> Fetch the complete documentation index at: https://docs.playflowcloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Lobby Events

> React to lobby and player state changes by subscribing to events from the PlayFlowLobbyManagerV2.

The `PlayFlowLobbyManagerV2` uses a system of `UnityEvent`s to communicate state changes and important occurrences to your game. By subscribing to these events, you can create a responsive UI and trigger game logic at the right moments.

All events are accessible through the `PlayFlowLobbyManagerV2.Instance.Events` property, which is an instance of `PlayFlowEvents`.

> [!NOTE]
>
> The `V2` in `PlayFlowLobbyManagerV2` is the SDK component version and is unrelated to the REST API version. Lobbies and matchmaking are served exclusively by the v3 engine API (`/api/v3/lobbies`); there is no v2 compatibility layer for them. These `UnityEvent`s are the SDK's abstraction over the server's real-time SSE event stream — you subscribe to C# events instead of parsing the raw stream yourself.

## Prerequisites

Before you wire up events, make sure you have:

* A lobby configuration and the `PlayFlowLobbyManagerV2` set up in your scene — see [Lobbies](https://docs.playflowcloud.com/unity/lobbies.md).
* Matchmaking modes (and optional match confirmation) configured if you use the matchmaking events — see [Matchmaking](https://docs.playflowcloud.com/unity/matchmaking.md).

## Subscribing to Events

You subscribe to events using the standard `AddListener` method. It's best practice to do this after the manager has been initialized.

```csharp theme={null}
using PlayFlow;
using UnityEngine;

public class MyLobbyUI : MonoBehaviour
{
    void Start()
    {
        // It's good practice to wait until the manager is ready
        PlayFlowLobbyManagerV2.Instance.Initialize("my-player-id", SubscribeToEvents);
    }

    void SubscribeToEvents()
    {
        var events = PlayFlowLobbyManagerV2.Instance.Events;
    
        // Fired when the local player joins a lobby
        events.OnLobbyJoined.AddListener(OnLobbyJoined);
    
        // Fired when another player joins the lobby
        events.OnPlayerJoined.AddListener(OnPlayerJoined);

        // Fired when a player leaves
        events.OnPlayerLeft.AddListener(OnPlayerLeft);
    
        // Fired when the lobby data is updated
        events.OnLobbyUpdated.AddListener(OnLobbyUpdated);

        // Fired on connection errors
        events.OnError.AddListener(OnError);
    }

    void OnLobbyJoined(Lobby lobby)
    {
        Debug.Log($"Successfully joined lobby: {lobby.name}");
        // Update UI to show lobby screen
    }

    void OnPlayerJoined(PlayerAction action)
    {
        Debug.Log($"Player {action.PlayerId} joined the lobby!");
        // Add player to UI list
    }

    void OnPlayerLeft(PlayerAction action)
    {
        Debug.Log($"Player {action.PlayerId} left the lobby.");
        // Remove player from UI list
    }

    void OnLobbyUpdated(Lobby lobby)
    {
        Debug.Log("Lobby data has been updated.");
        // Refresh the entire lobby UI
    }

    void OnError(string errorMessage)
    {
        Debug.LogError($"A PlayFlow error occurred: {errorMessage}");
        // Show an error popup to the user
    }

    void OnDisable()
    {
        // Don't forget to unsubscribe to prevent memory leaks!
        var events = PlayFlowLobbyManagerV2.Instance.Events;
        if (events != null)
        {
            events.OnLobbyJoined.RemoveListener(OnLobbyJoined);
            events.OnPlayerJoined.RemoveListener(OnPlayerJoined);
            events.OnPlayerLeft.RemoveListener(OnPlayerLeft);
            events.OnLobbyUpdated.RemoveListener(OnLobbyUpdated);
            events.OnError.RemoveListener(OnError);
        }
    }
}
```

## Event Reference

Here is a complete list of events available on `PlayFlowEvents`.

### Lobby Events

**OnLobbyCreated** `LobbyEvent` *required*

Fired when a lobby is successfully created by the local player. The event passes the created `Lobby` object.
*Argument: `Lobby`*

**OnLobbyJoined** `LobbyEvent` *required*

Fired when the local player successfully joins a lobby.
*Argument: `Lobby`*

**OnLobbyUpdated** `LobbyEvent` *required*

Fired whenever the `Lobby` data changes. This can be due to players joining/leaving, player state changes, or host actions.
*Argument: `Lobby`*

**OnLobbyLeft** `VoidEvent` *required*

Fired after the local player successfully leaves a lobby.
*Argument: `void`*

### Match Events

**OnMatchStarted** `LobbyEvent` *required*

Fired for all players in a lobby when the host starts the match (via `StartMatch()` or a completed matchmaking cycle). Status is now `in_game`, but the server is still `launching`.
*Argument: `Lobby`*

**OnMatchRunning** `ConnectionInfoEvent` *required*

Fired when the game server has finished booting and is ready to accept connections. The payload is a quick-access `ConnectionInfo` for the first port. For multi-port games use `lobby.TryGetPort("name", out var port)` instead.
*Argument: `ConnectionInfo`*

**OnMatchServerDetailsReady** `PortMappingInfoListEvent` *required*

Fires alongside `OnMatchRunning` with the **full list of ports** (name, protocol, host, internal/external port, TLS state). Subscribe to this when your game has more than one port (e.g. `game_udp` + `voice_tcp`).
*Argument: `List<PortMappingInfo>`*

**OnMatchEnded** `LobbyEvent` *required*

Fired for all players when a match ends — either the host called `EndMatch()`, or the server stopped on its own (TTL, crash, clean exit). The lobby auto-heals back to `waiting` with the same players and invite code, ready for a rematch.
*Argument: `Lobby`*

### Matchmaking Events

**OnMatchmakingStarted** `LobbyEvent` *required*

Fired when the lobby enters the matchmaking queue (after a successful `FindMatch()` call). Status is now `in_queue`.
*Argument: `Lobby`*

**OnQueueStats** `QueueStatsEvent` *required*

Fired roughly every 10 seconds while the lobby is searching, with live telemetry: total players searching, number of lobbies in queue, and average wait time. Perfect for a "42 players searching · \~12s wait" UI.
*Argument: `QueueStats`*

**OnMatchFound** `LobbyEvent` *required*

Fired when opponents are found and the match is committed. For modes **without** confirmation this fires right before `OnMatchStarted`. For modes **with** confirmation enabled, use `OnMatchAwaitingConfirmation` instead — `OnMatchFound` only fires after every lobby has accepted.
*Argument: `Lobby`*

**OnMatchAwaitingConfirmation** `LobbyEvent` *required*

Only relevant when the matchmaking mode has `matchConfirmation.enabled: true` in the dashboard. Fired when a match proposal is found — show a CS2-style "Accept Match" dialog. The lobby is in `match_found` status. Use `lobby.matchmaking.confirmation.deadline` (ISO 8601 timestamp) for the countdown.
*Argument: `Lobby`*

**OnMatchConfirmed** `LobbyEvent` *required*

Fired after `ConfirmMatch()` succeeds — your lobby has accepted. You're still waiting on other lobbies to confirm. Update your UI to show "Waiting on N other players…".
*Argument: `Lobby`*

**OnMatchDeclined** `LobbyEvent` *required*

Fired when the match proposal is cancelled — either someone called `DeclineMatch()`, or the confirmation window expired. All participating lobbies return to `waiting`. Show a "Match declined — click to re-queue" UI.
*Argument: `Lobby`*

**OnMatchmakingCancelled** `LobbyEvent` *required*

Fired when the host calls `CancelMatchmaking()` and the lobby returns to `waiting` voluntarily.
*Argument: `Lobby`*

**OnMatchmakingTimeout** `LobbyEvent` *required*

Fired when the matchmaking queue times out without finding a match. The lobby returns to `waiting`.
*Argument: `Lobby`*

### Player Events

**OnPlayerJoined** `PlayerEvent` *required*

Fired for all players in a lobby when a new player joins. The `PlayerAction` contains the ID of the player who joined.
*Argument: `PlayerAction`*

**OnPlayerLeft** `PlayerEvent` *required*

Fired for all players in a lobby when another player leaves. The `PlayerAction` contains the ID of the player who left.
*Argument: `PlayerAction`*

### System Events

**OnConnected** `VoidEvent` *required*

Fired when the client successfully connects to the PlayFlow service.
*Argument: `void`*

**OnDisconnected** `VoidEvent` *required*

Fired when the client disconnects from the PlayFlow service.
*Argument: `void`*

**OnError** `StringEvent` *required*

Fired when any error occurs within the SDK. Provides a string message describing the error.
*Argument: `string`*

### State Events

**OnStateChanged** `StateChangedEvent` *required*

Fired whenever the manager's internal state transitions (`Disconnected`, `Connecting`, `Connected`, `InLobby`, `InMatch`, etc.). Useful for gating UI flow — `(oldState, newState)`.
*Argument: `LobbyState`, `LobbyState`*


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.