Skill‑Based Matchmaking in Photon Realtime Using Custom Room Properties
Use Photon Realtime’s lobby‑visible custom properties to perform skill‑based matchmaking without a separate lobby. Set <code>CustomRoomPropertiesForLobby</code> on room creation and filter with <code>ExpectedCustomRoomProperties</code> in <code>OpJoinRandomRoom</code>.
13 Jul 2025, 07:43 UTC

Quick Takeaway
To implement lobby‑free skill‑based matchmaking in Photon Realtime, expose only the skill custom property on the room, then ask OpJoinRandomRoom for rooms that match the exact value you need. Photon will return only rooms whose lobby‑visible custom properties satisfy the filter, and the client will join the first match it finds.
How Photon Uses Custom Room Properties
Photon Realtime stores key‑value pairs on a room that can be read by all clients in that room. Two lists control what the server exposes to matchmaking:
CustomRoomProperties– all properties you want to set on the room.CustomRoomPropertiesForLobby– a subset that the server publishes to the lobby and uses forOpJoinRandomRoomfilters.
Only properties on CustomRoomPropertiesForLobby are considered when a client calls OpJoinRandomRoom with ExpectedCustomRoomProperties. The filter is an exact key‑value match; ranges or inequalities are not supported.
Configuring Rooms for Lobby‑Free Skill Matching
When you create a room, you must:
- Define the skill value you want to match on.
- Add that value to
CustomRoomProperties. - List the key in
CustomRoomPropertiesForLobbyso the matchmaking engine can see it.
Example:
// RoomOptions used when creating a skill‑based room
RoomOptions options = new RoomOptions
{
CustomRoomProperties = new Hashtable
{
{ "skill", 1500 } // integer skill rating
},
CustomRoomPropertiesForLobby = new string[] { "skill" }
};
client.OpCreateRoom(null, options); // null name = random room
After the room is created, the skill property is visible to matchmaking filters but hidden from the public room list unless you query it explicitly.
Joining with Expected Properties
When a client wants to find a room with a specific skill level, it sends the exact value in ExpectedCustomRoomProperties. Photon will return only rooms that have that value in a lobby‑visible property.
JoinRandomRoomParams joinParams = new JoinRandomRoomParams
{
ExpectedCustomRoomProperties = new Hashtable
{
{ "skill", 1500 } // look for rooms with skill 1500
}
};
client.OpJoinRandomRoom(joinParams);
Key points:
- Both the room creator and the joining client must use the same key name.
- The value must be serializable by Photon (int, string, bool, etc.).
- If no matching room exists, the call fails with
RoomNotFoundand you can create a new room instead.
Practical Example (C#)
Below is a minimal, self‑contained example that demonstrates creating two rooms with different skill values and then joining the one that matches a target skill.
using ExitGames.Client.Photon;
using ExitGames.Client.Photon.Realtime;
public class SkillMatchDemo
{
private Client client;
public void Connect()
{
client = new Client(new ClientAppSettings { AppIdRealtime = "YOUR_APP_ID" });
client.Connect();
}
public void CreateRooms()
{
// Room A – skill 1200
var optionsA = new RoomOptions
{
CustomRoomProperties = new Hashtable { { "skill", 1200 } },
CustomRoomPropertiesForLobby = new string[] { "skill" }
};
client.OpCreateRoom("RoomA", optionsA);
// Room B – skill 1500
var optionsB = new RoomOptions
{
CustomRoomProperties = new Hashtable { { "skill", 1500 } },
CustomRoomPropertiesForLobby = new string[] { "skill" }
};
client.OpCreateRoom("RoomB", optionsB);
}
public void JoinSkillRoom(int targetSkill)
{
var joinParams = new JoinRandomRoomParams
{
ExpectedCustomRoomProperties = new Hashtable { { "skill", targetSkill } }
};
client.OpJoinRandomRoom(joinParams);
}
}
After calling JoinSkillRoom(1500), the client will receive OnJoinedRoom for RoomB. If you call JoinSkillRoom(2000), the call fails, and you can decide to create a new room instead.
Limits & Common Pitfalls
| Issue | Cause | Fix |
|---|---|---|
| Filter returns no rooms | Property key not in CustomRoomPropertiesForLobby | Add key to the list when creating the room. |
| Unexpected room selection | Using non‑exact match (e.g., skill > 1500) | Photon only supports exact key‑value matches. Use multiple rooms or a server‑side filter if you need ranges. |
| Room property changes slow to propagate | Updating a lobby‑visible property via OpSetCustomProperties triggers callbacks but may take a frame. | Plan for eventual consistency; avoid frequent changes. |
| Security concerns | Clients can set any property when creating a room. | Validate critical matchmaking logic on a Photon Cloud plugin or dedicated server. |
Testing the Setup
- Create two rooms as shown above.
- Use a second client to call
OpJoinRandomRoomwithExpectedCustomRoomProperties = {"skill", 1500}. - Verify that
OnJoinedRoomfires forRoomBand thatOnRoomPropertiesUpdateshows theskillvalue. - Attempt a join with a non‑existent skill (e.g., 2000) and confirm the failure code
RoomNotFound.
When to Avoid This Pattern
- When you need range or inequality matching – Photon’s matchmaking filter does not support it.
- When you want to expose many changing game state values – custom properties are meant for static room metadata.
- When you require absolute security – rely on server‑side logic instead of client‑supplied properties.
Practical Checklist
- [ ] Verify that
CustomRoomPropertiesForLobbycontains every key you plan to filter on. - [ ] Ensure property values are of a simple Photon type.
- [ ] Handle
RoomNotFoundby creating a new room if no match exists. - [ ] Test in a controlled environment before rolling out to production.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.