Implementing Room-Based Matchmaking and State Sync in Photon Realtime
Learn how to implement room-based matchmaking and state synchronization in Photon Realtime using room properties, observable properties, and RPCs.
17 Dec 2025, 23:33 UTC

Multiplayer applications face a fundamental challenge: efficiently grouping players into sessions and ensuring all participants see a consistent game state. Photon Realtime addresses this using a 'Room' architecture, where a central server manages the lifecycle of a group and synchronizes data between clients. This guide demonstrates how to implement metadata-based matchmaking and state synchronization using observable properties.
Prerequisites
Before implementing the network layer, ensure the following are configured:
- Photon AppID: A Realtime-type ID generated from the Photon Dashboard.
- SDK Integration: The Photon SDK installed in your project (C#, Java, or C++).
- Event-Driven Architecture: A class structure capable of handling asynchronous callbacks.
Establishing Connection and Lifecycle Callbacks
Photon uses a ConnectionSettings object to define the network topology, including the AppId and AppVersion. To respond to network events, you must implement the RoomCallbacks interface, which listens for lifecycle events such as joining a room or disconnecting.
// Example implementation in C#
public class NetworkManager : MonoBehaviour, RoomCallbacks {
private LoadClient client;
void Start() {
ConnectionSettings settings = new ConnectionSettings() {
AppId = "YOUR_APP_ID_HERE",
AppVersion = "1.0",
};
client = new LoadClient();
client.Callbacks = this;
client.ConnectUsingSettings(settings);
}
public void OnConnected() {
// Triggered when the client successfully connects to the Photon server
Debug.Log("Connected to Server. Ready for matchmaking.");
}
public void OnJoinedRoom(Room room) {
// Triggered when the client successfully enters a room
Debug.Log($"Joined room: {room.RoomName}");
}
}
Matchmaking via Room Properties
Hardcoding room names is inefficient for scaling. Instead, use Room Properties—metadata key-value pairs—to filter rooms based on game parameters (e.g., map name or difficulty) before a client joins.
To create a room with specific matchmaking metadata, configure a CreateRoomRequest:
CreateRoomRequest request = new CreateRoomRequest() {
RoomName = "MapA_Lobby",
MaxPlayers = 4,
CustomProperties = new Dictionary<string, object>() {
{ "MapType", "Forest" },
{ "Difficulty", "Hard" }
}
};
client.CreateRoom(request);
Clients searching for a game should use FindRandomRoomRequest with a property filter. The server will only return rooms where the CustomProperties match the requested criteria, reducing the need for clients to join and leave rooms to find a match.
Synchronizing State: Observable Properties vs. RPCs
Once players are in a room, you must choose the correct synchronization method based on the data type. Photon provides two primary mechanisms: Observable Properties and Remote Procedure Calls (RPCs).
Observable Properties for Continuous State
Observable properties are designed for data that changes frequently, such as health points or coordinates. When a property is updated on one client, Photon automatically broadcasts the change to all other connected clients.
RPCs for Discrete Events
RPCs are used for "one-time" events, such as a player firing a weapon or sending a chat message. Because RPCs are asynchronous, developers must implement client-side prediction to mask network latency and prevent the game from feeling unresponsive.
| Method | Best Use Case | Sync Logic | Overhead |
|---|---|---|---|
| Observable Properties | High-frequency data (Health, Position) | Automatic on change | Low |
| RPCs | Instant events (Jump, Chat, Fire) | Manual call per event | Variable |
Verifying Synchronization and Performance
To ensure state synchronization is functioning correctly and within limits, perform the following checks:
- Multi-Client Test: Launch two instances of the application and join the same Room ID.
- Property Trigger: On Client A, update a property (e.g.,
room.SetCustomProperty("Health", 80)). Confirm that Client B'sOnPropertyChangedevent triggers and reflects the value 80. - CCU Monitoring: Check the Photon Dashboard to monitor Concurrent User (CCU) counts. Exceeding your subscription limit will result in connection rejections.
- Message Rate: Monitor the "Message Rate" metric in the dashboard to ensure high-frequency updates aren't saturating the bandwidth.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.