Source: https://gameye.com/unity-matchmaker-integration/

---
title: "Unity Matchmaker + Gameye: Dedicated Servers, No GSMS"
description: "Replace Unity GSMS with Gameye via Cloud Code. Keep your Matchmaker queues and rules. No egress fees, 0.5s session starts, 21 server providers globally."
---

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

Updated October 16, 2026

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

- Players submit match tickets — Unity Matchmaker runs your queue rules
- Match found — Unity Matchmaker invokes the Gameye Cloud Code module
- Module reads player latency attributes and selects the optimal Gameye region
- Module calls Gameye's Session API — server starts in the nearest datacenter (~0.5s)
- Module returns `ipv4Address` and `port` to Unity Matchmaker
- 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 it to Docker Hub or GitHub Container Registry (other OCI-compatible registries are available on request). Gameye pre-pulls images onto infrastructure — no cold-pull delay at session start.

Gameye API token

Start a Developer Trial at [trial.gameye.com](https://trial.gameye.com/). Self-serve signup. 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.production-gameye.gameye.net/available-location/your-image-name"
).SendWebRequest();
var locations = JsonUtility.FromJson(locResp.downloadHandler.text);

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

// Build ticket attributes — include Gameye latencies
var attributes = new Dictionary {
["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 {
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.production-gameye.gameye.net/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:      '1h',
}),
});

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.production-gameye.gameye.net/session/player/join
{ "sessionId": "session-id", "playerId": "player-id" }

# Player disconnected
POST https://api.production-gameye.gameye.net/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 found**Queue rules satisfied — Cloud Code module invoked

**Module creates Gameye session**~0.5s — returns host IP and port

**Players receive MatchAssignment via SDK**Direct connection — Gameye not in network path

**POST /session/player/join × N**Backend calls as players connect

**Match running**Gameye not in network path

**POST /session/player/leave × N**Backend calls as players disconnect

**Match ends → server exits → container reclaimed**Billing 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 **Register your Docker image with Gameye** — onboarding, no code changes required.
- 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 **Deploy the Cloud Code module** via UGS CLI — does not affect your live queue configuration yet.
- 4 **Clone your queue to a test queue** with `serverAllocation.type: cloudCode` pointing to the module.
- 5 **Route a small percentage of tickets** to the test queue via a feature flag in your ticket submission logic.
- 6 **Validate** — session starts, latency, cost metrics.
- 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

## Start your free trial today.

Sign up, push your image, and start your first session — all before your next sprint ends. No sales call required.

[Start Building →](https://trial.gameye.com/) [Integration docs →](https://gameye.com/docs/guides/integrations/unity-matchmaker/)

Further reading

- [All supported matchmaker integrations](https://gameye.com/matchmaker-integrations/)
- [Migrating from Unity Multiplay to Gameye](https://gameye.com/unity-multiplay-to-gameye/)
- [Gameye vs. Unity Multiplay — pricing and scaling comparison](https://gameye.com/gameye-vs-unity-multiplay/)
- [How Gameye orchestration works](https://gameye.com/how-it-works/)
