Decoupling Matchmaking Logic with Photon Custom Room Properties
Stop using concatenated strings for matchmaking. Learn how to use PhotonEngine's custom room properties to create flexible, skill-based matchmaking in Unity.
23 Mar 2026, 21:10 UTC

The Hard-Coded Matchmaking Trap
Many multiplayer developers start by creating a few static rooms—like "NorthAmerica_Beginner" or "Europe_Expert"—and forcing players to join based on a string match. This approach quickly collapses as you add more variables. If you want to filter by skill level, map preference, and game mode simultaneously, your room-naming logic becomes a tangled mess of concatenated strings that are difficult to maintain and impossible to query dynamically.
The solution is to move the matchmaking criteria out of the room name and into Custom Room Properties. These are key-value pairs stored on the Photon server that allow you to filter for compatible rooms without hard-coding the logic into the room's identity.
Defining Room Criteria via RoomOptions
Custom properties are defined during the room creation process using the RoomOptions class. Instead of relying on the server to just find "any" open room, you can specify exactly what attributes a room must have to be considered a match.
When a master client creates a room, they define a HasCustomProperties flag and specify the CustomRoomPropertiesCount. This tells the Photon server how much memory to allocate for the room's metadata. If you attempt to add more properties than you initially declared in the count, the operation will fail, which is why it is critical to estimate your metadata needs upfront.
Worked Example: Skill-Based Filtering in Unity
In this scenario, we want players to join a random room, but only if that room matches their specific skillTier. This ensures a balanced experience without requiring the player to manually select a lobby.
Implementation (C# / Unity):
using Photon.Pun; using Photon.Realtime; using Hashtable = ExitGames.Client.Photon.Hashtable;
public class MatchmakingManager : MonoBehaviourPunCallbacks
{
public void JoinSkillBasedRoom(int playerSkill)
{
// 1. Define the filter criteria
Hashtable expectedProperties = new Hashtable();
expectedProperties.Add("skillTier", playerSkill);
// 2. Use JoinRandomRoom with the custom properties filter
// This tells the server: "Find me any room where skillTier == playerSkill"
PhotonNetwork.JoinRandomRoom(expectedProperties);
}
public override void OnJoinRandomFailed(short returnCode)
{
Debug.Log("No matching room found. Creating a new one...");
CreateSkillRoom(3); // Example skill tier
}
private void CreateSkillRoom(int skill)
{
RoomOptions options = new RoomOptions();
options.MaxPlayers = 4;
options.HasCustomProperties = true;
options.CustomRoomPropertiesCount = 1;
// Set the property during creation
Hashtable customProps = new Hashtable();
customProps.Add("skillTier", skill);
options.CustomRoomProperties = customProps;
PhotonNetwork.CreateRoom("SkillRoom_" + Random.Range(0, 1000), options);
}
}
Execution Details:
- Where to run: This script should be attached to a persistent Manager object in your Unity scene.
- Permissions: Requires a valid Photon AppID configured in the PhotonServerSettings.
- Expected Result: The
OnJoinRandomFailedcallback will only trigger if no other room currently exists with the exactskillTiervalue provided.
Performance Trade-offs and Limitations
While custom properties are powerful, they are not a replacement for a full-scale backend database. Consider these constraints:
- Bandwidth Overhead: Every time a room property is updated, that data is synchronized to all clients in the room. Frequent updates to dynamic values (like a live score) can saturate the network.
- Property Limits: Photon typically limits the number of custom properties per room (often around 18). Overloading this limit can lead to connection errors or failed room creation.
- Stale Filters: Custom properties used for
JoinRandomRoomare checked at the moment of joining. If a room's properties change after a player has joined, the room may no longer match the original filter, but the player remains inside.
Verification and Testing
To verify your matchmaking logic is working as intended, do not rely solely on the Unity console. Open the Photon Dashboard and monitor the active rooms. You should see multiple rooms with different property values; verify that players with skillTier = 1 are never placed in rooms where the property is set to skillTier = 3.
If you need to roll back these changes, remove the expectedProperties argument from JoinRandomRoom() to return to basic, unfiltered matchmaking.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.