LogoLogo
edgegap.comDashboard
  • 📘Learning Center
    • Getting Started
    • Unity Games
      • Getting Started - Servers
      • Developer Tools
    • Unreal Engine Games
      • Getting Started - Servers
      • Developer Tools
    • Matchmaking
      • Getting Started
      • Matchmaker In-Depth
      • Ping Beacons
    • Advanced Features
      • Apps and Versions
      • Deployments
      • Managed Clusters
  • API Reference
    • Dedicated Servers
    • Integration
    • Matchmaking
    • Peer to Peer
  • Release Notes
  • 📚Documentation
    • Sample Projects
      • Unity Netcodes
        • Unity NGO
        • Photon Fusion 1
        • Photon Fusion 2
        • Mirror
        • Mirror WebGL
        • Fishnet
        • Fishnet WebGL
        • Photon Bolt
      • Unreal Top-Down Sample
      • NuxtJS
      • Ruby On Rails
      • Unity Lobbies
      • Unity Matchmaker
    • Tools & Integrations
      • Container
        • What is Docker
        • Your First Docker
        • The Good Practices
        • SSH in Your Container
        • External Registries
          • Docker Hub
          • AWS ECR
          • GCP GCR
          • Gitlab registry
      • Deploy from Nakama
      • EOS Lobby Integration
      • Switch From Gamelift
      • Switch From Multiplay
      • Playfab Bridge
    • Deployment
      • Endpoint Storage
        • How to Save Logs
        • Upload File to Deployment
      • Webhooks
    • Application
      • Command and Arguments
      • 1:1 Port Mapping
    • Session
      • How They Work
      • Application Version Configuration
      • Manage Request
      • Selectors Filtering
    • Fleet
      • Fleet Policy
      • Policy Filter
      • Linking Version
      • Fleet's Deployment
    • Container Registry
    • Distributed Relay
      • Matchmaker/Lobby
      • Relay Edgegap API
      • Transport Samples
    • Lobby
      • Lobby Service
      • Functions
    • Glossary
    • SLA Terms
Powered by GitBook
LogoLogo

Connect with Community

  • Discord
  • Linkedin
  • X

Read More

  • Release Notes
  • Blog
  • Enterprise
  • Legal
  • edgegap.com

© 2025 Edgegap

On this page
  • ✔️ Introduction
  • ⭐ Matchmaker Essentials
  • ☁️ Hosting Cluster
  • 📏 Configuration
  • Matchmaking Profiles
  • Matchmaking Rules
  • Matchmaking Teams
  • 🎫 Player Tickets
  • Matchmaking Process
  • Latencies Attributes
  • Join as Group
  • Backfill
  • 🔎 Server Browser
  • 📗 Matchmaking API
  • Authentication and Authorization
  • Server to Server Integration
  • Player API
  • Game Server API
  • 🟢 Operations & Observability
  • Injected Environment Variables
  • Rolling Updates & AB Tests
  • Player Traceability
  • Load Testing
  • Inspect API
  • Analytics and Insights
  • Support and Future Updates
  • 🚨 Troubleshooting
  • 🔖 Changelog

Was this helpful?

  1. Learning Center
  2. Matchmaking

Matchmaker In-Depth

PreviousGetting StartedNextPing Beacons

Last updated 8 days ago

Was this helpful?

Learn more about Edgegap’s no-code matchmaker concepts in-depth and customize to your needs.

✔️ Introduction

Edgegap Matchmaker is a managed service using your own rules to find the optimal group of teammates and opponents in seconds. Get started in 5 minutes and test the entire feature set for free. Upgrade when you're ready to a private dedicated cluster with enhanced security. Native integration with Edgegap Deployments delivers best-in-class ping no matter where your players are located.

Our matchmaking philosophy is driven by player perspective, with core principles of matchmaking:

  • social integration (such as friends and lobbies),

  • balance between match speed (time to play) and match quality (balanced player attributes),

  • high availability, process observability, and user-friendly error handling.

To deliver on our core principles, we prioritize first and foremost:

  • usability - ease of learning, integration, and use,

  • real world examples and troubleshooting guidelines,

  • modularity of features with holistic, design-driven approach,

  • full automation of DevOps and maintenance tasks.

Testing Matchmaker is entirely free, no credit card required. Free Tier allows up to 3 hours of runtime on our shared test cluster, after each restart. After releasing your game, your matchmaker will need to run 24/7 to ensure players across the world can join servers.

⭐ Matchmaker Essentials

There are three essential concepts to each Matchmaker:

  • ☁️ Hosting Cluster - underlying server infrastructure, fully managed and operated by Edgegap.

  • 📏 Configuration - set of rules and settings that define how the matchmaker will operate.

  • 🌐 Service Instance - the 24/7 live matchmaking service running on the Cluster, using Configuration to match players together and produce deployment (server) assignments.

☁️ Hosting Cluster

To make things easy, we host and manage matchmaking entirely for you 24/7. You can use our

  • Free Cluster (shared) to test all features and explore synergies with your design,

    • matchmakers on free cluster shut down after 3 hours automatically, requiring restart,

  • Private Cluster to ensure stable and dedicated environment for your production needs.

Private Cluster Tiers

Upgrading to a private cluster only takes one click. Changing Private Cluster Tiers after launch, without any player downtime, is also possible with Rolling Updates & AB Tests. Managed clusters provide you high-availability service hosting maintained by Edgegap.

Prepare for success and optimize after launch, so you don’t block your players on release day.

Our clusters use cloud machines featuring AMD/Intel CPUs with clock speed 2.4 - 3.2 GHz.

📏 Configuration

See Getting Started for our SDKs and detailed example scenarios.

Editing a running matchmaker will trigger a quick reload, deleting all tickets and causing short downtime.

Matchmaking Profiles

Profiles represent entirely separated matchmaking queues, only sharing the same matchmaker version. You can configure any number of profiles for your matchmakers, though splitting up your player base will result in longer queue times for your players.

Some game modes may require more vCPU / RAM, especially if they support a higher number of players. A single matchmaker may include multiple profiles, each linked to an app version with adjusted resources.

Application and Versions

Each matchmaker profile points to Apps and Versions in your Edgegap organization. Separating development and production environments with separate matchmaker may help prevent accidentally releasing a version which is not production ready.

Matchmaking Rules

Every ticket joins matchmaking queue based on initial rules defined for their chosen profile.

Rules

Each entry in profile at path .rules.initial represents a rule, where:

  • key is a string value to name the rule however you prefer; e.g. match_size , and

  • value is an object defining the type and attributes of the rule, adhering to our standard ruleset.

Operators player_count and latencies may only be used once per profile.

Operators (rule type)

To demonstrate various operators, we will refer to our example configuration:

All rules have to be met simultaneously to initiate assignment. You may match using operators:

player_count is a special rule defining how many players need to match to initiate assignment,

  • example defaults to 1 team (no team split), see Matchmaking Teams for more details,

player_count rule is required and may only be defined once in your initial configuration rules.

string_equality matches players with the exact same string value, case sensitively, e.g.:

  • example selected_game_mode rule:

    • Erin (”Capture The Flag”) and Frank (”capture the flag”) will not match; A≠B.

    • Charlie (”Capture The Flag”) and Dave (”Free For All”) will not match; A≠B,

    • Alice (”Free For All”) and Bob (”Free For All”) will match; A=B,

number_difference matches players within the absolute numerical difference from each other:

  • example elo_rating rule above with "max_difference": 50 initially:

    • Alice (42) and Bob (90) will match; | A-B |=48 elo_rating points,

    • Charlie (40) and Dave (91) will not match; | C-D |=51 elo_rating points.

intersection matches players with one or more overlapping string values, case sensitively:

  • example selected_region rule above with "overlap": 1 :

    • Alice [”NA”,”EU”] and Bob [”EU”,”APAC”] will match; A ∩ B = {“EU”},

    • Charlie [”NA”] and Dave [”EU”] will not match; C ∩ D = {}.

latencies is a special rule matching players within a specific difference range in ping values:

  • this presents a “soft” solution to splitting your player base, enabling matching with neighboring regions, especially improving match speed for less populated regions,

  • max_latency should be specified to discard locations above a given threshold,

    • example beacons rule above with "difference": 50, "max_latency": 250 initially:

      • Alice and Bob will match, since Beijing is discarded (>250) and the rest is within | A-B | < 50:

        • Alice {Montreal: 12.3, Newark: 45.6, Dallas: 59.9, Beijing: 264.4}; and

        • Bob {Montreal: 27.3, Newark: 32.4, Dallas: 23.1, Beijing: 252.2}.

      • Charlie and Dave will not match, since | C-D | > 50 for Dallas Beacon:

        • Alice {Montreal: 5.7 Newark: 44.2, Dallas: 59.5, Beijing: 263.2}; and

        • Bob {Montreal: 57.8, Newark: 32.0, Dallas: 24.2, Beijing: 272.3}.

    • See Ping Beacons and Latencies Attributes for details on player ticket integration.

Latencies rule is optional and may only be defined once in your initial configuration rules.

An openAPI specification will be generated based on your config once you create your matchmaker.

Rule Expansion

Optionally, expansions can be defined to modify each rule’s attributes at time intervals since ticket creation, effectively expanding the pool of players which can be matched, speeding up queue times.

In the example above, we expand the queue by modifying attributes after:

  • 5 seconds spent in queue:

    • elo_rating difference of 100 points is now accepted,

  • 10 seconds spent in queue:

    • elo_rating difference of 200 points is now accepted,

    • latency difference of 100 points is now accepted,

    • latency maximum of 250 points is now accepted,

  • 20 seconds spent in queue:

    • match_size of 3 players is now accepted,

  • 30 seconds spent in queue:

    • match_size of 2 players is now accepted,

  • 60 seconds spent in queue:

    • match_size of 1 players is now accepted

    • the match starts automatically.

Updates of the same rule’s attribute will overwrite previous values during rule expansion.

Matchmaking Teams

To support multiple teams, increase team_count value. Get total number of players by multiplying team size and team count:

  • for "team_count": 2 and "team_size": 5, a total of 10 players is required for a match,

  • for cooperative and free-for-all game modes, set "team_count": 1 .

Team IDs will be assigned to 🎫 Player Tickets (accessible by game clients), and injected in deployments as Injected Environment Variables (accessible by dedicated servers).

🎫 Player Tickets

Each player creates tickets to join the matchmaking queue. Tickets are compared and if criteria defined in the 📏 Configuration is met, a deployment will be assigned, and players may establish connection with game server.

Matchmaking Process

The matchmaking process can be summarized in a few steps:

  • Player creates a ticket status="SEARCHING" ,

  • Player repeatedly reads their ticket every second; looking for matches:

    1. Team has been found status="TEAM_FOUND" (see Matchmaking Teams and Join as Group),

      1. Optionally team disbanded status="SEARCHING" , shuffling groups.

      2. Optionally team disbanded status="SEARCHING" , teammate abandoned.

      3. Optionally group disbanded status="CANCELLED" , group member abandoned.

    2. Match has been found status="MATCH_FOUND" ,

    3. Host has been assigned status="HOST_ASSIGNED" ,

      1. Players read the assignment (URL & external port) from their tickets,

      2. Players retry connection to game server until ready.

  • Matchmaking may stop before "MATCH_FOUND" due to either:

    1. Player abandoning (deleting) their ticket,

      1. Ticket is immediately deleted and reading it will return 404 Not Found.

    2. Ticket expiration period reached status="CANCELLED" ,

      1. Ticket can be read until removal period is reached, then it’s deleted (returns 404).

    3. Maximum deployment retries exhausted status="CANCELLED" ,

      1. Ticket can be read until removal period is reached, then it’s deleted (returns 404).

If players experience any issues, or a long queue time, they may attempt deleting their current ticket and restarting the process by creating a new ticket.

If the player has been matched and assigned a game server, their ticket will be deleted automatically. Players who abandon queue after HOST_ASSIGNED may be replaced with server Backfill.

For best experience, provide status updates to players using in-game UI. Once players connect, start a loading scene to perform synchronization steps (e.g. selecting and loading a map/scene/level).

Latencies Attributes

{
  "Los Angeles": 224.4,
  "Manama": 23.2,
  "Tokyo": 167.4
}

Beacon latency values are used to prevent matching with players in a vastly different region.

Join as Group

Joining matchmaking with your friends relies on a third party identity system. Most games will use Epic Online Services, Nakama, Steamworks, brainCloud, Lootlocker, Playfab, Apple Identity, Google Play, or others… These systems usually expose a platform-dependent friend system and a lobby/party system which can be used to communicate across the group.

To join matchmaking with a group, once the group is assembled:

  • Group leader requests ticket attributes from other members,

  • Group members provide requested information to leader,

  • Group leader creates a Group Ticket using our SDKs or the API,

    1. upon receiving assignments, Group leader sends each member one assignment,

  • Group members follow regular Matchmaking Process as if they joined alone.

In case a group member decides to abandon their ticket prior to HOST_ASSIGNED, all tickets of group members immediately update to status="CANCELLED" pending removal after the configured period. Afterwards, this matchmaking process may be repeated from scratch with a new group ticket, disregarding the previous tickets.

If a group member decides to abandon match after HOST_ASSIGNED , game server is responsible for waiting for a pre-defined period of time and finally issuing new Backfill tickets to replace the player.

If a group member’s game client crashes, they may reconnect as long as they have saved their assignment ID persistently (on drive) between game restarts.

See Getting Started and our SDKs with automated reconnect and more.

Backfill

Optionally, some games may have special matchmaking needs, such as:

  • allow new players to join games in progress (friends or strangers),

  • replace players who leave (leavers) after game starts to avoid restarting match,

  • allow spectators to join and observe tournament or friends’ matches (e-sports),

  • centralize players in larger servers to provide more social interactions (MMOs),

  • let players choose a server to join through a server browser (custom).

Backfill is a server-controlled matchmaking feature enabling all of these use cases and more. Once Matchmaking Process and game server initialization concludes, your server should continually:

  • Start idle disconnect countdown for each new player (recommend up to 3 min):

    1. Start a loading scene/level while players connect - a full fledged 3D scene, a lobby-like social UI, or a loading screen with a progress bar, to indicate initialization is progressing.

    2. Trigger loading for new players on server initialization.

    3. Trigger loading for players replacing leavers (joining via Backfills).

  • Keep track of new player connections or existing players leaving over time:

    1. Read Injected Environment Variables for initial players' ticket data.

    2. Listen to custom client RPCs containing new player ticket IDs (initial or backfilled), to pair tickets to netcode entities/actors.

    3. Read and verify matchmaking data of players using Endpoint /backfills assignment.

    4. Create new Backfills for unused player capacity (leavers) or to renew expired Backfills.

🥛 Backfill Example (Simple Example)
{
  "profile": "simple-example",
  "attributes": {
	  "assignment": {
      "request_id": "cd28e6c66554",
      "fqdn": "cd28e6c66554.pr.edgegap.net",
      "ip_address": "192.168.2.14",
      "ports": {
        "game": {
          "internal": 7777,
          "external": 56890,
          "link": "cd28e6c66554.pr.edgegap.net:56890",
          "protocol": "UDP"
        },
        "web": {
          "internal": 22,
          "external": 57440,
          "link": "cd28e6c66554.pr.edgegap.net:57440",
          "protocol": "TCP"
        },
        "server": {
          "internal": 80,
          "external": 50110,
          "link": "cd28e6c66554.pr.edgegap.net:50110",
          "protocol": "TCP"
        }
      },
      "location": {
        "city": "Montreal",
        "country": "Canada",
        "continent": "North America",
        "administrative_division": "Quebec",
        "timezone": "America/Toronto"
      }
    }
  },
  "tickets": {
    "c3d057h5h6f7j889fk43": {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        }
      },
      "group_id": "192bb97e-7fd6-4d86-8ce4-61c53c9fef16",
      "id": "c3d057h5h6f7j889fk43",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqg0bg9583s738h9dkf6": {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        }
      },
      "group_id": "aea7df3c-d391-4ea3-a3ec-dded422fe7c8",
      "id": "cqg0bg9583s738h9dkf6",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqd0785f4ggffd99sk8n": {
      "player_ip": "136.224.30.243",
      "attributes": {
        "beacons": {
          "New York": 30.2,
          "Los Angeles": 10.5,
          "Paris": 123.9
        }
      },
      "group_id": "123er97e-7fd6-4d86-8ce4-61c53c9fet49",
      "id": "cqd0785f4ggffd99sk8n",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    }
  },
  "assigned_ticket": null
}
🥛 Backfill Assignment Example (Simple Example)
{
  "profile": "simple-example",
  "attributes": {
	  "assignment": {
      "request_id": "cd28e6c66554",
      "fqdn": "cd28e6c66554.pr.edgegap.net",
      "ip_address": "192.168.2.14",
      "ports": {
        "game": {
          "internal": 7777,
          "external": 56890,
          "link": "cd28e6c66554.pr.edgegap.net:56890",
          "protocol": "UDP"
        },
        "web": {
          "internal": 22,
          "external": 57440,
          "link": "cd28e6c66554.pr.edgegap.net:57440",
          "protocol": "TCP"
        },
        "server": {
          "internal": 80,
          "external": 50110,
          "link": "cd28e6c66554.pr.edgegap.net:50110",
          "protocol": "TCP"
        }
      },
      "location": {
        "city": "Montreal",
        "country": "Canada",
        "continent": "North America",
        "administrative_division": "Quebec",
        "timezone": "America/Toronto"
      }
    }
  },
  "tickets": {
    "c3d057h5h6f7j889fk43": {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        }
      },
      "group_id": "192bb97e-7fd6-4d86-8ce4-61c53c9fef16",
      "id": "c3d057h5h6f7j889fk43",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqg0bg9583s738h9dkf6": {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        }
      },
      "group_id": "aea7df3c-d391-4ea3-a3ec-dded422fe7c8",
      "id": "cqg0bg9583s738h9dkf6",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqd0785f4ggffd99sk8n": {
      "player_ip": "136.224.30.243",
      "attributes": {
        "beacons": {
          "New York": 30.2,
          "Los Angeles": 10.5,
          "Paris": 123.9
        }
      },
      "group_id": "123er97e-7fd6-4d86-8ce4-61c53c9fet49",
      "id": "cqd0785f4ggffd99sk8n",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    }
  },
  "assigned_ticket": {
	  "profile": "simple-example",
    "player_ip": "244.13.201.244",
    "attributes": {
      "beacons": {
        "New York": 30.2,
        "Los Angeles": 10.5,
        "Paris": 123.9
      }
    },
	  "id": "cqg0bg550h7uujd77khg",
	  "group_id": "e0cf41c0-f88f-456e-a032-03b1d6821a9a",
	  "created_at": "2024-08-20T13:38:08.251393+00:00",
	  "status": "SEARCHING"
	}
}

Use Backfill to replace Seat/Match sessions. Matchmaker only supports Default session type.

See Getting Started for genre-specific scenarios and examples.

🔎 Server Browser

This feature is in development, scheduled for late 2025, stay tuned for updates! 🚀

Some games may want to let players join servers with open capacity. We're working on additional matchmaking features allowing this in addition or as a replacement of classic matchmaking.

📗 Matchmaking API

Clients and servers may call API directly or via SDK methods, see also Getting Started.

Authentication and Authorization

Game clients and Servers authenticate with Matchmaker using an Authorization HTTP header containing your secret token (Auth Token). If you’re using our SDKs, an input is provided to paste your matchmaker-specific Auth Token.

Authorization: xxxxxxxx-e458-4592-b607-c2c28afd8b62

This token may be included in your game client safely, as it doesn't grant access to Edgegap API.

Keep your tokens secret and safe! Edgegap staff will never ask you for your tokens.

To restrict access to certain functions, authenticate players using a third party identity store (such as Epic Online Services, Steamworks, brainCloud, Nakama, Lootlocker, Apple Identity, Google Play Account, or others…) you may integrate an additional authorization service of your own using Server to Server Integration.

Server to Server Integration

If creating tickets for players using your own backend service, make sure to add an additional HTTP header X-Player-Ip with the player’s public IP address (or include parameter player_ip in ticket create API request) so Matchmaker can perform telemetry and ensure lowest possible latency.

Player API

These endpoints can be used directly by game clients or your Server to Server Integration.

Endpoint /monitor

Monitoring endpoint provides a convenient way to verify uptime of your Matchmaker Service from game clients or backend services, so you can reach out for assistance in case of urgent issues. You may integrate redundant (multiple) monitoring systems checking this endpoint for your own visibility.

🟢 Monitor Status (GET) Example
{
  "status": "HEALTHY",
  "message": "All systems operational.",
  "healthy_components": 5,
  "unhealthy_components": 0
}

Endpoint /locations/beacons

Ping Beacons provide a simple yet effective way to approximate connection quality to major networking nodes and prevent high latency matches. See Latencies Attributes for more.

🗼 Beacons List (GET) Example (Reduced Sample)
{
  "count": 5,
  "beacons": [
    {
      "fqdn": "b-1b67036359bc.pr.edgegap.net",
      "public_ip": "172.233.26.222",
      "tcp_port": 31709,
      "udp_port": 32126,
      "location": {
        "city": "Sao Paulo",
        "country": "Brazil",
        "continent": "South America",
        "administrative_division": "Sao Paulo",
        "timezone": "Brasília Time"
      }
    },
    {
      "fqdn": "b-7ef05f5f25f7.pr.edgegap.net",
      "public_ip": "172.104.9.206",
      "tcp_port": 30775,
      "udp_port": 31490,
      "location": {
        "city": "Newark",
        "country": "United States of America",
        "continent": "North America",
        "administrative_division": "New Jersey",
        "timezone": "Eastern Time"
      }
    },
    {
      "fqdn": "b-4c07a9a8369b.pr.edgegap.net",
      "public_ip": "157.175.50.63",
      "tcp_port": 30857,
      "udp_port": 32711,
      "location": {
        "city": "Manama",
        "country": "Bahrain",
        "continent": "Asia",
        "administrative_division": "Bahrain",
        "timezone": "Arabia Time"
      }
    }
    {
      "fqdn": "b-fe41a96156be.pr.edgegap.net",
      "public_ip": "172.234.123.158",
      "tcp_port": 30622,
      "udp_port": 30278,
      "location": {
        "city": "Stockholm",
        "country": "Sweden",
        "continent": "Europe",
        "administrative_division": "Stockholm County",
        "timezone": "Central European Time"
      }
    },
    {
      "fqdn": "b-ee0069bafee6.pr.edgegap.net",
      "public_ip": "172.105.204.125",
      "tcp_port": 32116,
      "udp_port": 32041,
      "location": {
        "city": "Tokyo",
        "country": "Japan",
        "continent": "Asia",
        "administrative_division": "Tokyo",
        "timezone": "Japan Time"
      }
    },
  ]
}

Endpoint /tickets

  • Create Ticket (POST) - pick a matchmaking profile & submit ticket attributes:

🍀 Simple Ticket Example (Minimal Recommended Configuration)
{
  "profile": "simple-example",
  "attributes": {
    "beacons": {
      "Montreal": 12.3,
      "Newark": 45.6,
      "Dallas": 59.9
    }
  }
}
  • Read a Ticket (GET) - check on matchmaking progress and host assignment.

🍀 Simple Assignment Example (Minimal Recommended Configuration)
{
  "id": "cqg0bg550h7uujd77khg",
  "profile": "simple-example",
  "group_id": "0ba34811-7f0d-4bf9-8b20-20d63e9c2640",
  "team_id": "cusf43gmsflc73beiijg",
  "assignment": {
    "fqdn": "cd28e6c66554.pr.edgegap.net",
    "public_ip": "192.168.2.14",
    "ports": {
      "game": {
        "internal": 7777,
        "external": 51123,
        "link": "cd28e6c66554.pr.edgegap.net:51123",
        "protocol": "UDP"
      },
      "web": {
        "internal": 8888,
        "external": 51456,
        "link": "cd28e6c66554.pr.edgegap.net:51456",
        "protocol": "TCP"
      }
    },
    "location": {
      "city": "Montreal",
      "country": "Canada",
      "continent": "North America",
      "administrative_division": "Quebec",
      "timezone": "America/Toronto"
    }
  },
  "created_at": "2024-08-20T13:38:08.251393+00:00",
  "status": "HOST_ASSIGNED"
}
  • Delete a Ticket (DELETE) - abandon matchmaking immediately.

Endpoint /group-tickets

Join as Group endpoints allows matching deployments as a group/party/lobby:

  • Create Group Ticket (POST) - submit yours and your group members' tickets.

    • Your designated group host/leader is responsible to collect ticket attributes from players through a third party of your choice, and to distribute assignment IDs to individual group members to allow managing individual Matchmaking Process.

🍀 Simple Group Ticket Example (Minimal Recommended Configuration)
{
  "player_tickets": [
    {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        }
      },
      "id": "c3d057h5h6f7j889fk43"
    },
    {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        }
      },
      "id": "cqg0bg9583s738h9dkf6"
    },
    {
      "player_ip": "136.224.30.243",
      "attributes": {
        "beacons": {
          "New York": 30.2,
          "Los Angeles": 10.5,
          "Paris": 123.9
        }
      },
      "id": "cqd0785f4ggffd99sk8n"
    }
  ]
}

See Join as Group for details and Getting Started for genre-specific scenarios.

Cross-Origin Resource Sharing (CORS)

To resolve this error, add allowed_cors_origin parameter to your configuration to either:

  • whitelist your exact client hosting domains:

🍀 Simple Example (Specific Domains Example)
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "allowed_cors_origins": [
    "https://dev.my-game-server.com",
    "https://prod.my-game-server.com"
  ],
  "profiles": {
    "simple-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 2
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 50,
              "max_latency": 200
            }
          }
        },
        "expansions": {}
      }
    }
  }
}
  • or whitelist a wildcard domain (including all subdomains):

🍀 Simple Example (Wildcard Domain Example)
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "allowed_cors_origins": ["https://*.my-game-server.com"],
  "profiles": {
    "simple-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 2
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 50,
              "max_latency": 200
            }
          }
        },
        "expansions": {}
      }
    }
  }
}

No credentials are required for Matchmaker pre-flight requests, if domains are configured correctly.

Game Server API

These endpoints are used by the dedicated game server or your game backend.

Endpoint /backfills

Backfill allows your game server or your backend service to manage player capacity of servers:

  • Create a Backfill (POST) - submit current player tickets along with matchmaking profile.

🥛 Backfill Example (Simple Example)
{
  "profile": "simple-example",
  "attributes": {
    "assignment": {
      "request_id": "cd28e6c66554",
      "fqdn": "cd28e6c66554.pr.edgegap.net",
      "ip_address": "192.168.2.14",
      "ports": {
        "game": {
          "internal": 7777,
          "external": 56890,
          "link": "cd28e6c66554.pr.edgegap.net:56890",
          "protocol": "UDP"
        },
        "web": {
          "internal": 22,
          "external": 57440,
          "link": "cd28e6c66554.pr.edgegap.net:57440",
          "protocol": "TCP"
        },
        "server": {
          "internal": 80,
          "external": 50110,
          "link": "cd28e6c66554.pr.edgegap.net:50110",
          "protocol": "TCP"
        }
      },
      "location": {
        "city": "Montreal",
        "country": "Canada",
        "continent": "North America",
        "administrative_division": "Quebec",
        "timezone": "America/Toronto"
      }
    }
  },
  "tickets": {
    "c3d057h5h6f7j889fk43": {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        }
      },
      "group_id": "192bb97e-7fd6-4d86-8ce4-61c53c9fef16",
      "id": "c3d057h5h6f7j889fk43",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqg0bg9583s738h9dkf6": {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        }
      },
      "group_id": "aea7df3c-d391-4ea3-a3ec-dded422fe7c8",
      "id": "cqg0bg9583s738h9dkf6",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqd0785f4ggffd99sk8n": {
      "player_ip": "136.224.30.243",
      "attributes": {
        "beacons": {
          "New York": 30.2,
          "Los Angeles": 10.5,
          "Paris": 123.9
        }
      },
      "group_id": "123er97e-7fd6-4d86-8ce4-61c53c9fet49",
      "id": "cqd0785f4ggffd99sk8n",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    }
  },
  "assigned_ticket": null
}
  • Read a Backfill (GET) - retrieve ticket information about the filled player.

🥛 Backfill Assignment Example (Simple Example)
{
  "profile": "simple-example",
  "attributes": {
    "assignment": {
      "request_id": "cd28e6c66554",
      "fqdn": "cd28e6c66554.pr.edgegap.net",
      "ip_address": "192.168.2.14",
      "ports": {
        "game": {
          "internal": 7777,
          "external": 56890,
          "link": "cd28e6c66554.pr.edgegap.net:56890",
          "protocol": "UDP"
        },
        "web": {
          "internal": 22,
          "external": 57440,
          "link": "cd28e6c66554.pr.edgegap.net:57440",
          "protocol": "TCP"
        },
        "server": {
          "internal": 80,
          "external": 50110,
          "link": "cd28e6c66554.pr.edgegap.net:50110",
          "protocol": "TCP"
        }
      },
      "location": {
        "city": "Montreal",
        "country": "Canada",
        "continent": "North America",
        "administrative_division": "Quebec",
        "timezone": "America/Toronto"
      }
    }
  },
  "tickets": {
    "c3d057h5h6f7j889fk43": {
      "player_ip": "174.25.48.238",
      "attributes": {
        "beacons": {
          "New York": 12.2,
          "Los Angeles": 45.3,
          "Paris": 78.3
        }
      },
      "group_id": "192bb97e-7fd6-4d86-8ce4-61c53c9fef16",
      "id": "c3d057h5h6f7j889fk43",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqg0bg9583s738h9dkf6": {
      "player_ip": "217.34.85.142",
      "attributes": {
        "beacons": {
          "New York": 21.0,
          "Los Angeles": 30.2,
          "Paris": 101.1
        }
      },
      "group_id": "aea7df3c-d391-4ea3-a3ec-dded422fe7c8",
      "id": "cqg0bg9583s738h9dkf6",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    },
    "cqd0785f4ggffd99sk8n": {
      "player_ip": "136.224.30.243",
      "attributes": {
        "beacons": {
          "New York": 30.2,
          "Los Angeles": 10.5,
          "Paris": 123.9
        }
      },
      "group_id": "123er97e-7fd6-4d86-8ce4-61c53c9fet49",
      "id": "cqd0785f4ggffd99sk8n",
      "created_at": "2024-08-20T13:38:05.251393+00:00"
    }
  },
  "assigned_ticket": {
    "profile": "simple-example",
    "player_ip": "244.13.201.244",
    "attributes": {
      "beacons": {
        "New York": 30.2,
        "Los Angeles": 10.5,
        "Paris": 123.9
      }
    },
    "id": "cqg0bg550h7uujd77khg",
    "group_id": "e0cf41c0-f88f-456e-a032-03b1d6821a9a",
    "created_at": "2024-08-20T13:38:08.251393+00:00",
    "status": "SEARCHING"
  }
}
  • Delete a Backfill (DELETE) - stop backfill depending on game server logic and design.

See Backfill for details and Getting Started for genre-specific scenarios.

Endpoint /inspect

Inspect API lets developers understand and debug possible matchmaking flows:

  • Inspect Tickets (GET) - list current player tickets, their status, and assignment (if available).

🎫 Inspect Tickets Example (Simple Example)
{
  "data": [
    {
      "id": "cusemi0msflc73beiicg",
      "profile": "simple-example",
      "group_id": "53ff24e1-cea9-4317-9eca-a15b1b35bc72",
      "team_id": null,
      "player_ip": "174.93.233.25",
      "assignment": null,
      "created_at": "2025-02-21T21:08:24.2528685Z",
      "status": "SEARCHING"
    },
    {
      "id": "cusem7omsflc73beiiag",
      "profile": "simple-example",
      "group_id": "d25f4886-bfe1-4959-a06e-0e03d04567ca",
      "team_id": "cusemi8msflc73beiidg",
      "player_ip": "174.93.233.25",
      "assignment": null,
      "created_at": "2025-02-21T21:07:43.3824185Z",
      "status": "MATCH_FOUND"
    },
    {
      "id": "cusemhgmsflc73beiibg",
      "profile": "simple-example",
      "group_id": "b5d6a00a-b295-42c6-9bfa-a0feac95dfb0",
      "team_id": "cusemi8msflc73beiidg",
      "player_ip": "174.93.233.25",
      "assignment": null,
      "created_at": "2025-02-21T21:08:22.9357005Z",
      "status": "MATCH_FOUND"
    }
  ],
  "total_count": 3,
  "pagination": {
    "number": 1,
    "next_page_number": null,
    "previous_page_number": null,
    "paginator": {
      "num_pages": 1
    },
    "has_next": false,
    "has_previous": false
  }
}
  • Inspect Matches (GET) - list current matches and resolved Matchmaking Rules values.

👥 Inspect Matches Example (Simple Example)
{
  "data": [
    {
      "id": "matchac085106-1b0c-4519-bb8e-5646c7547356",
      "teams": [
        {
          "id": "cusepkomsflc73beiig0",
          "players": [
            {
              "id": "cusep10msflc73beiie0",
              "profile": "simple-example",
              "group_id": "3fb0b1e5-5566-46d3-b2cc-132131d1160b",
              "team_id": "cusepkomsflc73beiig0",
              "player_ip": "174.93.233.25",
              "assignment": {
                "fqdn": "2821bb04b41b.pr.edgegap.net",
                "public_ip": "69.164.212.65",
                "ports": {
                  "gameport": {
                    "internal": 5000,
                    "external": 30813,
                    "link": "2821bb04b41b.pr.edgegap.net:30813",
                    "protocol": "HTTP"
                  }
                },
                "location": {
                  "city": "Newark",
                  "country": "United States of America",
                  "continent": "North America",
                  "administrative_division": "New Jersey",
                  "timezone": "Eastern Time"
                }
              },
              "created_at": "2025-02-21T21:13:40.4821087Z",
              "status": "HOST_ASSIGNED"
            },
            {
              "id": "cusepkgmsflc73beiif0",
              "profile": "simple-example",
              "group_id": "90762249-fcc4-42dc-968f-4b8d83534647",
              "team_id": "cusepkomsflc73beiig0",
              "player_ip": "174.93.233.25",
              "assignment": {
                "fqdn": "2821bb04b41b.pr.edgegap.net",
                "public_ip": "69.164.212.65",
                "ports": {
                  "gameport": {
                    "internal": 5000,
                    "external": 30813,
                    "link": "2821bb04b41b.pr.edgegap.net:30813",
                    "protocol": "HTTP"
                  }
                },
                "location": {
                  "city": "Newark",
                  "country": "United States of America",
                  "continent": "North America",
                  "administrative_division": "New Jersey",
                  "timezone": "Eastern Time"
                }
              },
              "created_at": "2025-02-21T21:14:58.3907649Z",
              "status": "HOST_ASSIGNED"
            }
          ]
        }
      ]
    }
  ],
  "total_count": 1,
  "pagination": {
    "number": 1,
    "next_page_number": null,
    "previous_page_number": null,
    "paginator": {
      "num_pages": 1
    },
    "has_next": false,
    "has_previous": false
  }
}

🟢 Operations & Observability

To pass information to game servers and provide operational insights, we provide additional features.

Injected Environment Variables

🏁 Advanced Example Variables (Complete Example)
MM_MATCH_PROFILE=simple-example
MM_EXPANSION=initial
MM_TICKET_IDS=["cusfn10msflc73beiik0","cusfn18msflc73beiil0"]
MM_TICKET_cusfn10msflc73beiik0={"player_ip":"174.93.233.25","group_id":"b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1","team_id":"cusfn1gmsflc73beiim0","attributes":{"beacons":{"Montreal":12.3,"Toronto":45.6,"Quebec":78.9},"elo_rating":1337,"selected_game_mode":"quickplay","selected_map":["Dust II","Airport","Bank Vault"],"selected_region":["North America","Europe"]}}
MM_TICKET_cusfn18msflc73beiil0={"player_ip":"174.93.233.23","group_id":"015d4dc8-6c79-4b5c-bbc6-f309b9787c8f","team_id":"cusfn1gmsflc73beiim0","attributes":{"beacons":{"Montreal":12.3,"Toronto":45.6,"Quebec":78.9},"elo_rating":1339,"selected_game_mode":"quickplay","selected_map":["Overpass","Airport"],"selected_region":["North America"]}}
MM_GROUPS={"b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1":["cusfn10msflc73beiik0"],"015d4dc8-6c79-4b5c-bbc6-f309b9787c8f":["cusfn18msflc73beiil0"]}
MM_TEAMS={"cusfn1gmsflc73beiim0":["b2080c27-19c9-4fb0-8fe7-4bf1e5d285d1","015d4dc8-6c79-4b5c-bbc6-f309b9787c8f"]}
MM_MATCH_ID=simple-example_initial-2025-02-21T22:17:43.3886970Z
MM_INTERSECTION={"selected_map":["Airport"],"selected_region":["North America"]}
MM_EQUALITY={"selected_game_mode":"quickplay"}

Map players to tickets - players should send their ticket ID to game server when they connect.

Environment variables are stored as stringified JSONs, parse them using an SDK or a custom method.

Rolling Updates & AB Tests

Keeping track of compatibility between server and client versions can get confusing. Follow our tips for reliable releases, updates, and preventing downtime or compatibility issues.

Your Matchmaker URL will always remain the same after restarting.

Create separate matchmakers for dev & production environments to safeguard against human error.

🟠 Before Going Live

To prepare for zero-downtime updates we recommend creating at least 3x copies of your matchmaking profile ahead of time, for example green, blue and orange. Each game client version will create tickets for one of these, rotating after each update.

Multiple app versions can serve as aliases for the same server image tag, removing the need to restart your matchmaker when rolling out a new server version. Simply update the tag of your app version.

🔃 Client + Server Update

This section assumes you’ve completed 🟠 Before Going Live. Let’s assume that live game clients (c1) are currently connecting to profile green, pointing to app version green linked with image tag v1.1.0. We also assume you’ve previously created profile blue pointing to app version blue linked with an older image tag which is no longer used (e.g. v1.0.2).

In order to release game client + server updates, you may:

  • Prepare new server app version (v1.2.0) on Edgegap:

    1. push a new image tag to your container registry (v1.2.0),

    2. create new app version (v1.2.0),

    3. optionally enable caching for new app version (v1.2.0) in preparation,

    4. wait for cache percentage to get to 80% or higher,

    1. connect your game engine’s Editor to the provided URL + external port,

  • Update unused profile blue to link to your new image tag (v1.2.0),

  • Update your new game client (c2) to use the new profile (blue) when creating tickets:

    1. change the base URL and Authorization token to production matchmaker values,

  • Perform QA tests and final verifications of your new game client (c2):

    1. if you find and resolve any issues, repeat process from the beginning,

  • Release your new game client update (c2) on distribution platforms,

  • Allow time for new game client (c2) to distribute to player devices (typically up to 3-7 days):

  • Perform cleanup of unused resources in your Edgegap account:

    1. delete app version v1.2.0 as it’s no longer used for dev tests,

    2. delete image tag v1.1.0 to free up Container Registry capacity since update is completed.

For your next update, increase version numbers and swap green and blue keywords in the guide.

⚡ Server Hotfix

This section assumes you’ve completed 🟠 Before Going Live. Let’s assume that live game clients (c1) are currently connecting to profile green, pointing to app version green linked with image tag v1.1.0.

To release a server patch without requiring a game client update, you may:

  • Prepare new server app version (v1.2.0) on Edgegap:

    1. push a new image tag to your container registry (v1.2.0),

    2. create new app version (v1.2.0),

    3. optionally enable caching for new app version (v1.2.0) in preparation,

    4. wait for cache percentage to get to 80% or higher,

    1. connect your game engine’s Editor to the provided URL + external port,

    2. if you find and resolve any issues, repeat process from step 1,

  • Update currently used profile green to link to your new image tag (v1.2.0),

    1. new matches will automatically initiate assignment with the updated tag (v1.2.0),

  • Perform cleanup of unused resources in your Edgegap account:

    1. delete app version v1.2.0 as it’s no longer used for dev tests,

    2. delete image tag v1.1.0 to free up Container Registry capacity since update is completed.

Player Traceability

Display ticket IDs and deployment IDs in client match history UI to trace players when troubleshooting.

Load Testing

The resource requirements for your instance will depend on factors:

  • number of players - more players make more tickets,

  • number of requests - polling for status more often creates more load on matchmaker,

  • configuration complexity - number of profiles, rules, and expansions,

  • average match duration - shorter duration means more matches, tickets, and higher load,

  • ticket expiration and removal periods - keeping stale tickets for longer consumes more memory,

  • client retry fallback logic - retrying with short jittered backoff helps spread traffic burst peaks.

If a matchmaker is experiencing high load:

  • if CPU is throttling, matchmaking could be slowed down,

  • if matchmaker runs out of memory, it will restart without losing ticket information, hoping that clients will implement exponential backoff and the burst is retried over longer period of time.

Inspect API

Matchmaker offers a vast set of capabilities, adding complexity to the matchmaking process. The changes you make to your configuration and the impact on your players will be more predictable if you run tests on your matchmaker, using our Inspect API:

  • List all tickets to understand and reset state quickly and reliably anytime.

  • List match proposals for live tickets to fine tune your ruleset and gain more control.

  • Coming Soon: pause and resume matchmaking at specific ticket stages.

Analytics and Insights

This feature is in development, scheduled for 2025, stay tuned for updates! 🚀

To improve user experience we plan to expose additional user-facing statistics through our SDKs and API. Additionally, some studios may want to optimize and monitor their Matchmakers. To address both needs, we plan to expose metrics such as:

  • load monitoring over time (create, read, delete, expire),

  • match speed and expansions per profile,

  • groups and teams attribute balance,

  • bucketing based on attributes and rules (min, max, avg over time),

  • event data export for your custom analysis needs.

Support and Future Updates

🚨 Troubleshooting

Error with profiles. Message: The application configuration is not valid for profile XYZ.
  • Please verify your application name and version in config profiles.

Why am I getting errors when trying to create a new matchmaker?
Why did my matchmaker turned off automatically after 3 hours?
  • Consider upgrading to paid tier for unliminted runtime.

Why can’t I start a second deployment on my account?
  • You may only run 1 concurrent deployment in Free Tier.

  • Please consider upgrading to paid tier for unlimited deployments.

Why am I getting assignment/deployment at random times, disregarding player_count?
My ticket is stuck in SEARCHING .
  • Please verify you’ve created enough matching tickets adhering to your configuration.

My ticket is stuck switching between `MATCH_FOUND` and TEAM_FOUND repeatedly.
  • Free Tier accounts are limited to 1 deployment at a time.

  • Please consider upgrading or stop your current deployment to start a new one.

My ticket goes straight to CANCELLED.
  • Your ticket reached it’s expiration. Create a new ticket or increase the expiration period in your configuration for testing purposes.

I receive HTTP 404 Not Found when checking on my ticket.
  • Your ticket was removed either by a DELETE request, or by reaching it’s removal period (starts after ticket is expired, defined in your configuration). Recreate a new ticket or increase the expiration/removal periods in your configuration for testing purposes.

My matchmaker shows an error, what should I do?

🔖 Changelog

Semantic Versioning

Your configuration file will be validated depending on matchmaker version used, make sure your rules are matching the matchmaker version’s capabilities.

The latest version of matchmaker is 2.1.0. All examples on this page are up to date. Keep an eye out for end of support notices for your matchmaker version. See also Rolling Updates & AB Tests.

2.1.0 (Feb 24, 2025)

This is the latest matchmaker service version, recommended for production use.

Stop, Edit, and Start your matchmaker to upgrade to new major version. Quick Restart won't do it.

⚠️ Breaking changes:

  • Separated game profile and expansion stage information in the Injected Environment Variables:

    • MM_MATCH_PROFILE will now only include the profile name as it appears in the configuration.

    • Introduced MM_EXPANSION_STAGE which will contain the expansion stage as a string (e.g. "initial", "15", "30").

  • Ticket assignments now include the group ID when Endpoint /tickets. Group ID is also included as an Injected Environment Variables, as a mapping of group ID to a list of the group's player IDs.

  • Ticket assignments now include the team ID when Endpoint /tickets. The team ID is also included in every ticket data Injected Environment Variables.

  • Endpoint /tickets now returns 409 Conflict HTTP code instead of 204 No Content to indicate the ticket can't be deleted since the deployment is starting. To replace leavers, use a Backfill issued by the server after a pre-specified timeout period.

  • Endpoint /backfills request body parameter attributes.deployment_request_id has been moved to attributes.assignment.request_id.

  • Endpoint /backfills request body now requires full assignment details as part of attributes parameter in addition to the request_id.

🩹 Bugfixes:

  • Resolved intersection rule values are now Injected Environment Variables in the MM_INTERSECTION environment variable.

  • Quick restart feature now reliably regenerates API endpoints and openAPI specification when configuration is changed.

  • Fixed several bugs during matchmaker (re)start causing prolonged startup time or getting matchmaker stuck.

✨ Improvements and new features:

  • Increased rate limits and scalability of all API endpoints, across all matchmaker tiers.

  • When assigning a player to a Backfill, the new player's ticket ID will be added as a tag to the Backfill's Deployments.

  • Added swagger UI authentication feature to test API directly in web UI without needing postman.

  • Improved openAPI examples to reflect realistic requests and responses more closely.

  • Added new Inspect API meant for development and debugging purposes.

    • Allows listing all current player tickets in a paginated list.

    • Allows listing all current matches in a paginated list.

1.0.0 (Dec 9, 2024)

  • Backfill: Upon (popular) request, we’re adding backfill with automated ticket assignment, which allows you to reuse server seats when players leave the session.

    • Ideal for filling empty player seats after a match has begun, or for replacing players that have left during a match.

  • Join as Group: We’re adding the ability to join as a group to the already available ability to fill multiple teams with players.

    • Ideal for joining up in a matchmaking queue with a group of friends or coming from a common lobby.

    • To make integration easier, we’re now offering Software Development Kits for the most popular game engines.

  • Fixed a bug where the Latencies Attributes was not applied correctly.

  • Tickets will now be automatically canceled after a Matchmaking Process if they haven't been assigned to a deployment.

  • You can now Endpoint /tickets to enhance the flow of your matchmaking process.

  • Deployments made by the matchmaker are now tagged with ticket IDs.

  • You can now edit your configuration while the matchmaker is running. This triggers a quick reload of your configuration without requiring a full on/off cycle for your matchmaker. Note: This feature is not recommended for production environments, as it deletes all current tickets and temporarily makes the API unresponsive.

  • Fixed Injected Environment Variables to use the correct primitive types instead of arrays.

  • Fixed Injected Environment Variables JSON values, which previously contained escaped characters.

0.2.3 (Oct 8, 2024)

  • Fixed a bug where certain headers were not accepted by the matchmaker when requests were made from a WebGL application (CORS policies).

0.2.2 (Oct 3, 2024)

  • Fixed issue with TLS/SSL certificate validation preventing matchmaker from launching.

0.2.1 (Sep 30, 2024)

  • Fixed a bug causing the beacons endpoint to return a 500 error.

0.2.0 (Sep 25, 2024)

  • Basic authentication is now mandatory for all endpoints.

  • Added the ability to configure the number of retries on server assignment failure.

  • Team-based matchmaking is now the default for all matchmaking configurations.

  • Both application and version are now required fields in all profiles.

  • Introduced a new endpoint to monitor the matchmaker's status.

  • Updated the format of the tickets environment variable in the deployment.

  • Added a configuration option to allow hosts to communicate with the matchmaker.

  • The debug API is now only available when explicitly enabled in the configuration (it is currently disabled for rework).

  • The game_profile key in the GET ticket response has been replaced by profile.

To take advantage of new features and bug fixes, you’ll need to .

Every matchmaker is based on JSON configuration.

When used with Join as Group, groups will match in teams with sufficient slots without overfilling. Teams are balanced using average (mean) of attributes. Interested in alternatives?

, waiting while Assignment is null,

Deployment may be retried several times if occurs,

, server process starts initializing,

To provide best possible latency, 🎫 Player Tickets may include game clients’ for one or more Ping Beacons. Once clients perform a “best effort” measurement, they construct an object with all beacon-specific latency values:

See our for “join as group” inspiration.

Delete any leftover Backfills once the :

Unity - callback,

Unreal - or callback.

See and for player connection monitoring.

To Backfill a group of players, or invite a friend to an existing game, add Matchmaking Profiles with a string_equality operator following the example, sharing the same app version. Current player tickets will be matched using the chosen profile to new player tickets. Any profile can be used for Backfill as long as attributes of backfill are valid.

If you need a server browser feature urgently, consider using our API to .

VPNs mask player IP addresses. Game clients may use free service to find their real public IPs.

🎫 Player Tickets provide a simple interface for players to match together, see Matchmaking Process and .

override by attaching player_ip parameter in your ticket.

Unity/Android - consider to prevent code stripping of hardcoded JSONs.

For webGL games hosted on third party distribution platforms (e.g. ), sending any requests to Matchmaker from game client may result in policy violations. Most modern web browsers send a to verify that a backend service (the Matchmaker) understands and accepts communication from your game client.

Failing pre-flight check (default for security reasons) can result in , most commonly CORS header 'Access-Control-Allow-Origin' missing .

Your server might need to know details about it’s players. Ticket attributes, resolved rule values, and other values are injected to your deployment, in addition to default .

, then disable underperforming variants, and keep the 🏆 winner version.

We recommend the for update releases.

Perform any dev tests by (v1.2.0):

monitor outdated game clients (c1) by with app version (green),

Perform tests and verifications by (v1.2.0):

If your players experience any issues, tracing their path to server logs can be helpful. Each Matchmaker deployment will be tagged with assigned player ticket IDs so you can easily and find to help you troubleshoot.

See to learn about deployment troubleshooting.

Instances use CPU and memory to perform matchmaking and assignments, associating a hosting cost with each private matchmaker. See resources and prices associated with each tier on .

Always use for stress testing. Free matchmakers are limited for testing at small scale only.

Use or implement exponential jittered backoff to recover from high load.

Your success is our priority. If you'd like to send custom requests, ask for missing critical features , or express any thoughts, .

Please read the error, it’s possible you’ve misspelled an identifier, rule, or an operator. - Use to validate your JSON formatting, you may have missed a comma or a bracket. - Reach out over for help, we’ll be happy to assist. 🙏

Matchmakers in Free Tier are intended for initial tests and are automatically turned off after 3 hours. To continue testing you may .

You or another team member may have created tickets during a previous testing session which were not assigned. Please .

If this is a development or a testing instance, try restarting your matchmaker first. - Please report any issues through .

In case this issue is impacting a live game, create an .

Our matchmaker uses official guidelines. Each configuration JSON is tied to a specific version of the matchmaker. Matchmaker version dictates which rules and settings are available in your configuration and API. Once a version is released, it will never change.

and matchmaking SDKs:

📘
Config is validated automatically during restarts.
Let us know!
Epic Online Services group implementation example
OnApplicationQuit
OnWorldDestroyed
PreExit
Mirror Seat Management
FishNet Seat Management
Reach out to let us know about your server browser requirements and needs!
ipify.org
using raw string interpolation
itch.io
Cross-Origin Resource Sharing
pre-flight request
one of several possible CORS-related errors
Run AB tests
blue/green strategy
deploying your new app version
filtering deployments
deploying your new app version
our pricing page
please reach out in our Community Discord
JSONLint
our Community Discord
restart your matchmaker
restart your matchmaker
our Community Discord
urgent support request
Semantic Versioning
update your matchmaker version
private clusters
⭐ Matchmaking SDK
⚡ Edgegap Integration Kit by Betide Studio
⭐ Matchmaking SDK
4. Deployment Error
5. Deployment Stopped
Filter Deployments
📍 Server Placement
Injected Environment Variables
Filter Deployments
Container Logs
🟢 Connection Quality
latency
Deployment started
Deployment is Ready

If you need help, . For live games support see our .

We currently offer to cater to everybody’s needs:

Tier
Hobbyist Tier
Studio Tier
Enterprise Tier

See for your first steps with Matchmaker, game integration, and detailed examples.

See for your first steps with Matchmaker, game integration, and detailed examples.

See for your first steps with Matchmaker, game integration, and detailed examples.

🎾 Custom Lobby Example
🏁 Advanced Example (Complete Example Configuration)
🏁 Advanced Example (Complete Example Configuration)
🏁 Advanced Example (Complete Example Configuration)
🍀 Simple Example (Minimal Recommended Configuration)
🎈 Social Game Example

High beacon ping doesn’t equate to high server ping. Servers are available in more locations than beacons. Beacons are orchestrated in real time to prioritize best coverage, low data transfer, and fast measurement.

See for automated ping measurement using our SDKs. Learn how to start low and increase the allowed latency gradually with .

{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "profiles": {
    "custom-lobby-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 4
            }
          },
          "lobby_id": {
            "type": "string_equality"
          }
        },
        "expansions": {}
      }
    }
  }
}
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "allowed_cors_origins": ["https://*.my-game-server.com"],
  "profiles": {
    "advanced-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 50,
              "max_latency": 80
            }
          },
          "elo_rating": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 50
            }
          },
          "selected_game_mode": {
            "type": "string_equality"
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "selected_region": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "5": {
            "elo_rating": {
              "max_difference": 100
            }
          },
          "10": {
            "elo_rating": {
              "max_difference": 200
            },
            "beacons": {
              "difference": 100,
              "max_latency": 250
            }
          },
          "20": {
            "match_size": {
              "team_count": 1,
              "team_size": 3
            }
          },
          "30": {
            "match_size": {
              "team_count": 1,
              "team_size": 2
            }
          },
          "60": {
            "match_size": {
              "team_count": 1,
              "team_size": 1
            }
          }
        }
      }
    }
  }
}
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "allowed_cors_origins": ["https://*.my-game-server.com"],
  "profiles": {
    "advanced-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 50,
              "max_latency": 80
            }
          },
          "elo_rating": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 50
            }
          },
          "selected_game_mode": {
            "type": "string_equality"
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "selected_region": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "5": {
            "elo_rating": {
              "max_difference": 100
            }
          },
          "10": {
            "elo_rating": {
              "max_difference": 200
            },
            "beacons": {
              "difference": 100,
              "max_latency": 250
            }
          },
          "20": {
            "match_size": {
              "team_count": 1,
              "team_size": 3
            }
          },
          "30": {
            "match_size": {
              "team_count": 1,
              "team_size": 2
            }
          },
          "60": {
            "match_size": {
              "team_count": 1,
              "team_size": 1
            }
          }
        }
      }
    }
  }
}
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "allowed_cors_origins": ["https://*.my-game-server.com"],
  "profiles": {
    "advanced-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 50,
              "max_latency": 80
            }
          },
          "elo_rating": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 50
            }
          },
          "selected_game_mode": {
            "type": "string_equality"
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "selected_region": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "5": {
            "elo_rating": {
              "max_difference": 100
            }
          },
          "10": {
            "elo_rating": {
              "max_difference": 200
            },
            "beacons": {
              "difference": 100,
              "max_latency": 250
            }
          },
          "20": {
            "match_size": {
              "team_count": 1,
              "team_size": 3
            }
          },
          "30": {
            "match_size": {
              "team_count": 1,
              "team_size": 2
            }
          },
          "60": {
            "match_size": {
              "team_count": 1,
              "team_size": 1
            }
          }
        }
      }
    }
  }
}
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "profiles": {
    "simple-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 2
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 50,
              "max_latency": 200
            }
          }
        },
        "expansions": {}
      }
    }
  }
}
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "profiles": {
    "social-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "attributes": {
              "team_count": 1,
              "team_size": 30
            },
            "type": "player_count"
          },
          "beacons": {
            "attributes": {
              "difference": 80,
              "max_latency": 80
            },
            "type": "latencies"
          },
          "selected_region": {
            "type": "string_equality"
          },
          "selected_mode": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "10": {
            "beacons": {
              "difference": 100,
              "max_latency": 100
            },
            "match_size": {
              "team_count": 1,
              "team_size": 20
            }
          },
          "15": {
            "beacons": {
              "difference": 120,
              "max_latency": 120
            },
            "match_size": {
              "team_count": 1,
              "team_size": 10
            }
          },
          "25": {
            "match_size": {
              "team_count": 1,
              "team_size": 4
            }
          },
          "30": {
            "match_size": {
              "team_count": 1,
              "team_size": 1
            }
          }
        }
      }
    }
  }
}
Getting Started
Getting Started
Getting Started
Getting Started
Rule Expansion

Beacons are automatically rescaled in real time - adding/removing/replacing existing beacons. Your clients and backend should account for this and reload list of beacons before each matchmaking round.

See also 🟢 Connection Quality and 🚨 Troubleshooting for deployments.

please reach out to us over Discord
ticketing system

Best Suited For

enthusiasts, solo developers

commercial releases

high-traffic launches

Resources

1 vCPU + 2GB RAM

6 vCPU + 12GB RAM

18 vCPU + 48GB RAM

Redundancy

1x virtual node

3x virtual nodes

3x virtual nodes

Price (hourly)

$0.0312

$0.146

$0.548

Price (30 days)

$22.464

$105.12

$394.56

3 private cluster tiers

To create a Backfill-only profile, specify your regular matchmaking rules and set match_size to 999,999. Backfills ignore player count rules, always matching with 1 player ticket.

To create a Backfill-only profile, specify your regular matchmaking rules and set match_size to 999,999. Backfills ignore player count rules, always matching with 1 player ticket.

Use or to get variable values.

🤝 Cooperative Game Example
⚔️ Competitive Game Example
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "profiles": {
    "cooperative-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 60,
              "max_latency": 60
            }
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "selected_difficulty": {
            "type": "string_equality"
          },
          "player_level": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 10
            }
          }
        },
        "expansions": {
          "5": {
            "beacons": {
              "difference": 80,
              "max_latency": 80
            }
          },
          "10": {
            "player_level": {
              "max_difference": 20
            }
          },
          "20": {
            "match_size": {
              "team_count": 1,
              "team_size": 3
            },
            "beacons": {
              "difference": 100,
              "max_latency": 100
            }
          },
          "30": {
            "match_size": {
              "team_count": 1,
              "team_size": 2
            },
            "beacons": {
              "max_latency": 200
            }
          },
          "60": {
            "match_size": {
              "team_count": 1,
              "team_size": 1
            }
          }
        }
      }
    },
    "cheater-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 1,
              "team_size": 4
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 60,
              "max_latency": 60
            }
          },
          "selected_map": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "selected_difficulty": {
            "type": "string_equality"
          },
          "player_level": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 10
            }
          }
        },
        "expansions": {
          "5": {
            "beacons": {
              "difference": 80,
              "max_latency": 80
            }
          },
          "10": {
            "player_level": {
              "max_difference": 20
            }
          },
          "20": {
            "match_size": {
              "team_count": 1,
              "team_size": 3
            },
            "beacons": {
              "difference": 100,
              "max_latency": 100
            }
          },
          "30": {
            "match_size": {
              "team_count": 1,
              "team_size": 2
            },
            "beacons": {
              "max_latency": 200
            }
          },
          "60": {
            "match_size": {
              "team_count": 1,
              "team_size": 1
            }
          }
        }
      }
    }
  }
}
{
  "version": "2.1.0",
  "inspect": true,
  "max_deployment_retry_count": 3,
  "ticket_expiration_period": "5m",
  "ticket_removal_period": "1m",
  "profiles": {
    "casual-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 25,
              "max_latency": 100
            }
          },
          "league_rank": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 1
            }
          },
          "selected_maps": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "selected_beacons": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "10": {
            "beacons": {
              "difference": 40,
              "max_latency": 150
            }
          },
          "30": {
            "beacons": {
              "difference": 50
            }
          },
          "60": {
            "league_rank": {
              "max_difference": 2
            }
          },
          "180": {
            "beacons": {
              "difference": 100,
              "max_latency": 500
            }
          }
        }
      }
    },
    "competitive-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 25,
              "max_latency": 100
            }
          },
          "league_rank": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 0
            }
          },
          "selected_maps": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "selected_beacons": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "30": {
            "beacons": {
              "difference": 40,
              "max_latency": 150
            }
          },
          "60": {
            "beacons": {
              "difference": 50
            }
          },
          "180": {
            "beacons": {
              "max_latency": 250
            }
          }
        }
      }
    },
    "challenger-example": {
      "application": {
        "name": "my-game-server",
        "version": "2024.01.30-16.23.00-UTC"
      },
      "rules": {
        "initial": {
          "match_size": {
            "type": "player_count",
            "attributes": {
              "team_count": 2,
              "team_size": 5
            }
          },
          "beacons": {
            "type": "latencies",
            "attributes": {
              "difference": 25,
              "max_latency": 100
            }
          },
          "league_rank": {
            "type": "number_difference",
            "attributes": {
              "max_difference": 0
            }
          },
          "selected_maps": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          },
          "selected_beacons": {
            "type": "intersection",
            "attributes": {
              "overlap": 1
            }
          }
        },
        "expansions": {
          "30": {
            "beacons": {
              "difference": 40,
              "max_latency": 150
            }
          },
          "180": {
            "beacons": {
              "difference": 50
            }
          },
          "240": {
            "beacons": {
              "max_latency": 250
            }
          }
        }
      }
    }
  }
}
GetEnvironmentVariable in C#
GetEnvironmentVariable in C++

Swagger Web UI: deploying a matchmaker will generate an openAPI specification and a convenient web UI. Open the URL in your browser to view and test all API endpoints, and to review payload examples.

🎾 Custom Lobby
5. Game Integration