Using Photon Realtime Custom Room Properties for Dynamic Matchmaking
Find out how to use Photon Realtime’s custom room properties for dynamic matchmaking—set criteria on room creation, query with JoinRandomRoom, and keep everything inside Photon’s fast server. Includes a Unity example, trade‑offs, and next steps.
30 Nov 2025, 05:13 UTC

The Problem: Matchmaking Without an External Service
When building a real‑time multiplayer game, you often need to pair players by skill, region, or game mode. Relying on a separate matchmaking server adds latency, maintenance overhead, and a single point of failure. Photon Realtime offers a built‑in way to filter rooms on the server by using custom room properties, letting you keep matchmaking logic close to the game logic.
Photon’s Custom Properties: A Quick Primer
Photon Realtime exposes two key/value stores that are replicated across the network:
- Room custom properties – shared by all players in a room.
- Player custom properties – specific to each player.
Both are implemented as Hashtable objects that can contain primitive types (int, float, bool, string) and arrays of those types. When you set a property, the server serializes the change and pushes it to all clients instantly.
Setting a Property
// Inside a room
var props = new Hashtable { { "skill", 3 }, { "mode", "deathmatch" } };
PhotonNetwork.CurrentRoom.SetCustomProperties(props);
To change a single value, you can pass a Hashtable with just that key.
Querying Rooms
When you want to join a room that matches certain criteria, you can pass the same key/value pairs to JoinRandomRoom. Photon’s server filters the room list before the client receives any matches.
var filter = new Hashtable { { "skill", 3 } };
PhotonNetwork.JoinRandomRoom(filter, null);
If no room satisfies the filter, the callback OnJoinRandomFailed is invoked and you can create a new room instead.
Building a Matchmaking Flow With Properties
Below is a minimal Unity example that demonstrates the full round‑trip: create a room with a skill level, query for a room with the same skill, and verify that the client joins the correct room.
using ExitGames.Client.Photon;
using Photon.Pun;
using UnityEngine;
public class Matchmaker : MonoBehaviourPunCallbacks
{
[SerializeField] private int mySkill = 3;
private void Start()
{
PhotonNetwork.ConnectUsingSettings();
}
public override void OnConnectedToMaster()
{
// Try to join a room with the same skill
var filter = new Hashtable { { "skill", mySkill } };
PhotonNetwork.JoinRandomRoom(filter, null);
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
// No matching room – create one
var roomOptions = new RoomOptions { MaxPlayers = 8 };
var props = new Hashtable { { "skill", mySkill } };
PhotonNetwork.CreateRoom(null, roomOptions, props);
}
public override void OnJoinedRoom()
{
Debug.Log($"Joined room {PhotonNetwork.CurrentRoom.Name} with skill {PhotonNetwork.CurrentRoom.CustomProperties["skill"]}");
}
}
Key points to verify after running this script:
- Open the Photon Dashboard, navigate to Rooms, and confirm that only rooms with the matching
skillvalue appear in the filtered list. - Inspect the
Custom Propertiescolumn to see theskillvalue. - Check the Unity console for the
OnJoinedRoomlog to confirm the client joined the expected room.
Trade‑offs & Limitations
| Aspect | Consideration |
|---|---|
| Property Size | All custom properties together must stay under 4 KB per room. Large or frequently changing data can increase serialization overhead. |
| Supported Types | Only primitive types and arrays of primitives are allowed. Complex objects must be serialized to a string (e.g., JSON) before storing. |
| Server Load | Filtering is lightweight, but a very large number of rooms with many properties can still impact lookup performance. |
| Stale Data | When a property is updated, older values are not automatically removed. Use the removeExisting flag if you need to replace a property cleanly. |
In practice, the typical use case—small numeric or string values like skill levels or mode identifiers—fits comfortably within these constraints.
Actionable Next Steps
- Define your matchmaking schema: Decide which attributes (skill, region, mode) will be stored as room properties.
- Implement property setting on room creation: Ensure every new room sets the required properties immediately after creation.
- Use
JoinRandomRoomwith filters for each matchmaking attempt. Handle theOnJoinRandomFailedcallback to create a room when none match. - Monitor the Photon Dashboard to verify that rooms appear with the expected properties and that the filter logic works.
- For advanced scenarios, consider custom room property callbacks to react to property changes in real time.
By embedding matchmaking criteria directly into room properties, you keep the matchmaking logic within Photon’s high‑performance infrastructure, reduce external dependencies, and maintain a clean, scalable architecture for your multiplayer game.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.