Matchmaker Integration

Gameye + Unity Matchmaker

Cloud Code module. Keep your queues and rules. Replace Unity GSMS. Dedicated server sessions in under 0.5 seconds.

Unity Matchmaker Cloud Code module UGS CLI deploy No egress fees

Unity Matchmaker is a capable rules-based matchmaking service — skill brackets, team composition, latency thresholds, custom attributes. If you've built your matchmaking logic in Unity Matchmaker queues, it works. There's no reason to rebuild it.

What Unity GSMS (Game Server Managed Services) doesn't give you well is coverage and cost: egress fees, limited datacenter footprint, and tight coupling to the Unity platform are what drive studios to look for alternatives. The Gameye + Unity Matchmaker integration separates the two concerns cleanly: Unity Matchmaker finds the match, Gameye starts the server — via a Cloud Code module that deploys in under 15 minutes.

How it works
  1. Players submit match tickets — Unity Matchmaker runs your queue rules
  2. Match found — Unity Matchmaker invokes the Gameye Cloud Code module
  3. Module reads player latency attributes and selects the optimal Gameye region
  4. Module calls Gameye's Session API — server starts in the nearest datacenter (~0.5s)
  5. Module returns ipv4Address and port to Unity Matchmaker
  6. Players receive a MatchAssignment via the Unity Matchmaker SDK and connect directly

What changes vs. Unity GSMS

Unity Matchmaker + GSMS Unity Matchmaker + Gameye
Matchmaking rules Unity Matchmaker Unity Matchmaker (unchanged)
Server allocation Unity GSMS fleet Gameye Session API via Cloud Code
Server location Unity Multiplay datacenters 21 providers, 200+ locations
Egress fees ~$0.08/GB None
Session start time 30s–5min (VM provisioning) ~0.5 seconds (pre-pulled containers)
Engine SDK required Unity GSMS Server SDK None — plain Linux process
Infrastructure lock-in Unity platform Provider-agnostic

The key change in your codebase: one Cloud Code module that calls POST /session instead of allocating a Unity GSMS server. Everything upstream — queue configuration, pool rules, ticket submission, player SDK — is identical.


What you need

Linux server binary

Gameye uses container-based orchestration — the game server must compile to a Linux headless binary. Unity supports this via the Standalone Linux build target with the Dedicated Server module installed.

Docker image

Package your Linux binary as a Docker image and push to any OCI-compatible registry (Docker Hub, GitLab Registry, ECR). Gameye pre-pulls images onto infrastructure — no cold-pull delay at session start.

Gameye API token

Request sandbox access at /get-access/. Provisioned within 24 hours. Your image is registered during onboarding.

UGS CLI and project

You need an active Unity Gaming Services project with Unity Matchmaker enabled. Install the UGS CLI (npm i -g ugs) to deploy the Cloud Code module.


Integration

1

Store your Gameye token as a Cloud Code secret

The Cloud Code module needs your Gameye API token at runtime. Store it as a secret via the UGS CLI — never hardcode it in the module source.

Shell
# Authenticate with UGS
ugs login

# Store Gameye token as a Cloud Code secret
ugs cloud-code secrets create GAMEYE_API_TOKEN   --value "your-gameye-api-token"   --project-id $UNITY_PROJECT_ID   --environment-name production

Secrets are injected into the module's context.secrets object at invocation time and are never exposed in logs or module source.

2

Collect Gameye region latency in your game client

Gameye exposes pingable IPs per region via the GET /available-location endpoint. Have clients measure latency to these before submitting a match ticket and pass the results as custom playerAttributes. The Cloud Code module uses them to select the optimal server location for the match.

C# (Unity client)
// Fetch available Gameye regions for your image
var locResp = await UnityWebRequest.Get(
    "https://api.gameye.io/available-location/your-image-name"
).SendWebRequest();
var locations = JsonUtility.FromJson<LocationList>(locResp.downloadHandler.text);

// Measure round-trip latency to each region's pingable IP
var latencies = new Dictionary<string, float>();
foreach (var loc in locations.items) {
    latencies[loc.location] = await PingAsync(loc.latencyIp); // ms
}

// Build ticket attributes — include Gameye latencies
var attributes = new Dictionary<string, object> {
    ["skill"]              = player.mmr,
    ["gameye_europe_ms"]   = latencies.GetValueOrDefault("europe",   9999f),
    ["gameye_useast_ms"]   = latencies.GetValueOrDefault("us-east",  9999f),
    ["gameye_asia_ms"]     = latencies.GetValueOrDefault("asia-east",9999f),
};

// Submit the ticket
await MatchmakerService.Instance.CreateTicketAsync(
    new List<Unity.Services.Matchmaker.Models.Player> {
        new(AuthenticationService.Instance.PlayerId, attributes)
    },
    new CreateTicketOptions { QueueName = "ranked-queue" }
);
3

Deploy the Cloud Code module

Create the allocation module. Unity Matchmaker calls it with the full match payload — teams, players, and their attributes. The module selects the best Gameye region, starts the session, and returns the connection details.

JavaScript (Cloud Code module)
// gameye-allocator/index.js
// Deploy with: ugs cloud-code modules deploy ./gameye-allocator/

module.exports = {
  async Allocate({ params, context, logger }) {
    const { matchId, teams } = params;
    const players = teams.flatMap(t => t.players);

    // Select region with lowest worst-case latency across all players
    const region = selectBestRegion(players);
    logger.info(`Starting Gameye session in ${region} for match ${matchId}`);

    const res = await fetch('https://api.gameye.io/session', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${context.secrets.GAMEYE_API_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        location: region,
        image:    'your-image-name',
        version:  context.projectConfig.GAME_VERSION,
        args:     ['-dedicatedServer', `-maxPlayers=${players.length}`],
        labels:   { match_id: matchId },
        ttl:      3600,
      }),
    });

    if (!res.ok) {
      throw new Error(`Gameye session API error: ${res.status}`);
    }

    const session = await res.json();
    // session.host  → IP address
    // session.ports → [{ type: 'udp', container: 7777, host: 34521 }]
    const port = session.ports.find(p => p.type === 'udp').host;

    // Return format expected by Unity Matchmaker
    return { ipv4Address: session.host, port: String(port) };
  }
};

function selectBestRegion(players) {
  const regions = {
    'europe':    'gameye_europe_ms',
    'us-east':   'gameye_useast_ms',
    'asia-east': 'gameye_asia_ms',
  };
  return Object.entries(regions)
    .map(([region, attr]) => ({
      region,
      worstMs: Math.max(...players.map(p => p.attributes?.[attr] ?? 9999))
    }))
    .sort((a, b) => a.worstMs - b.worstMs)[0].region;
}
Shell — deploy
# Deploy the module to your UGS project
ugs cloud-code modules deploy ./gameye-allocator/   --project-id $UNITY_PROJECT_ID   --environment-name production

# Confirm deployment
ugs cloud-code modules list   --project-id $UNITY_PROJECT_ID   --environment-name production

Port mapping. The external port in ports[].host is what players connect to — it is not always 7777. Always use the value from the session response, not a hardcoded port.

4

Configure your Unity Matchmaker queue

Update your queue configuration in the UGS Dashboard (or via CLI) to use Cloud Code allocation. Point it to the Allocate function in the module you just deployed.

JSON — queue config excerpt
{
  "name": "ranked-queue",
  "defaultEscalationRules": [],
  "pools": [
    {
      "name": "default",
      "matchLogic": {
        "type": "Sequence",
        "rules": [
          { "type": "TeamCountRule", "min": 2, "max": 2 },
          { "type": "TeamSizeRule",  "min": 5, "max": 5 }
        ]
      },
      "teams": [
        { "name": "team-a", "minPlayers": 5, "maxPlayers": 5 },
        { "name": "team-b", "minPlayers": 5, "maxPlayers": 5 }
      ],
      "serverAllocation": {
        "type": "cloudCode",
        "cloudCodeConfig": {
          "moduleName": "gameye-allocator",
          "functionName": "Allocate"
        }
      }
    }
  ]
}

Existing queues. You can update a live queue's serverAllocation config without disrupting in-flight tickets. Tickets already matched are not affected; new matches immediately use the Cloud Code allocator.

5

Track session lifecycle

Call Gameye's player join and leave endpoints from your game server or backend when players connect and disconnect. This gives you accurate player counts and enables correct billing on process exit:

HTTP
# Player connected
POST https://api.gameye.io/session/player/join
{ "sessionId": "session-id", "playerId": "player-id" }

# Player disconnected
POST https://api.gameye.io/session/player/leave
{ "sessionId": "session-id", "playerId": "player-id" }

When the match ends, your server exits cleanly. Gameye detects process exit and reclaims the container. The ttl on the session is a backstop for any server that fails to exit.


Session lifecycle

Unity Matchmaker: match foundQueue rules satisfied — Cloud Code module invoked
Module creates Gameye session~0.5s — returns host IP and port
Players receive MatchAssignment via SDKDirect connection — Gameye not in network path
POST /session/player/join × NBackend calls as players connect
Match runningGameye not in network path
POST /session/player/leave × NBackend calls as players disconnect
Match ends → server exits → container reclaimedBilling stops on process exit

Migration from Unity GSMS

If your game is live on Unity Matchmaker + GSMS today, this migration can be done without player-facing downtime:

  1. 1
    Register your Docker image with Gameye — onboarding, no code changes required.
  2. 2
    Remove the Unity GSMS Server SDK from your game server binary — Gameye doesn't need it. Your server becomes a plain Linux process.
  3. 3
    Deploy the Cloud Code module via UGS CLI — does not affect your live queue configuration yet.
  4. 4
    Clone your queue to a test queue with serverAllocation.type: cloudCode pointing to the module.
  5. 5
    Route a small percentage of tickets to the test queue via a feature flag in your ticket submission logic.
  6. 6
    Validate — session starts, latency, cost metrics.
  7. 7
    Update your production queue to the Cloud Code allocator and decommission your GSMS fleet.

Your Unity Matchmaker queue rules, player SDK integration, and ticket submission code are identical between the GSMS queue and the Gameye queue — there is nothing to rewrite.


Frequently asked questions

Can I use Unity Matchmaker without Unity GSMS?

Yes. Unity Matchmaker supports custom server allocation via a Cloud Code module. When a match is found, Unity Matchmaker invokes the module, which calls Gameye's Session API. Players still receive a MatchAssignment via the Unity Matchmaker SDK — the flow is identical from the player's perspective.

Do I need to rewrite my Unity Matchmaker queues?

No. Your queue configuration, pool rules, and ticket submission code are unchanged. The only change is updating serverAllocation.type from multiplay to cloudCode and pointing it to the Gameye allocator module.

How does region selection work?

Gameye exposes pingable IPs per region via the GET /available-location endpoint. Game clients measure latency to these IPs before submitting a ticket and include them as custom playerAttributes. The Cloud Code module reads those measurements from the matched players, selects the region with the lowest worst-case latency, and passes it to POST /session.

Does my game server need the Unity GSMS Server SDK?

No. Gameye runs your server as a plain Linux process inside a container — no Unity GSMS Server SDK, no Gameye SDK. You can remove the Unity GSMS lifecycle SDK from your server project entirely. Player state is tracked via your backend calling the Gameye /session/player/join and /session/player/leave endpoints.

How long does the Cloud Code module deployment take?

The module deploys in under 15 minutes using the UGS CLI. Once deployed, you update your queue configuration via the UGS Dashboard or CLI. No redeployment of your game client or server binary is required — only the Cloud Code module and queue config change.

Does this work with Unity Matchmaker backfill?

Yes. For backfill, configure a separate Cloud Code function (or a conditional branch in Allocate) that checks whether a session already exists for the match. If it does, return the existing host and port from your data store rather than creating a new session. Unity Matchmaker delivers the MatchAssignment to the new player — no new server starts.

Get started

Sandbox access in 24 hours.

Request your API token, push your image, and start your first session — all before your next sprint ends. No sales call required.