Skip to main content
The PlayFlowLobbyManagerV2 uses a system of UnityEvents 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.

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.
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