What the relay really costs
Online friend rooms connect phone to phone (DIRECT) when they can. When they can't, the game falls back to our relay on the VM, and every byte the relay sends out is billed by Azure. Everything below comes from the live relay's own room log (every room since 27 Oct), the phones' telemetry, the match reports, and the VM itself. Where a number is a guess, the page says so.
Since 28 Oct (protocol 141/143) no friend link stayed on the relay. It carried 1.2 % of link-minutes, short spells while a phone changed network.
For the current build, plus the same again coming in. That's about 72 MB an hour, or about 36 MB per player. The 27 Oct relayed rooms measured 0.62-0.70 MB/min out.
At a 10 % relay share with typical use. $4.2 at 25 %, $17 if every room were relayed. Heavy play costs 4x that.
The relay container's 1-CPU cap is the limit, not the network (6,250 Mbps NIC). If the burstable VM runs out of CPU credits, this ceiling drops.
2 · Bytes per relayed player per minute
"Out" is what the relay sends, which Azure bills. "In" is what it receives, which is free. A relayed link moves the host's snapshots to the joiner (30 a second) and the joiner's inputs to the host (60 a second). The host is relayed for free with its joiners: its traffic is the same bytes in the other direction.
Measured on the live relay (relayed rooms, 27 Oct)
| Room | Secs | Host → relay | Joiner → relay | Relay out (both) | MB/min out |
|---|---|---|---|---|---|
| DYXLRV | 84 | 8.1 KB/s | 2.5 KB/s | 10.2 KB/s | 0.61 |
| GCYJAZ | 89 | 9.6 | 2.5 | 11.7 | 0.70 |
| TYJAGH | 73 | 9.6 | 2.4 | 11.6 | 0.70 |
| LETVDJ (mobile) | 195 | 6.2 | 2.1 | 9.7 | 0.58 |
| SPKKMC (mobile) | 124 | 7.6 | 2.1 | 10.0 | 0.60 |
| BXWYNH (mobile) | 130 | 5.9 | 1.9 | 9.0 | 0.54 |
App bytes as the relay counts them, without IP/UDP headers. The test app's 27 Oct snapshots were lighter than today's.
Projected for today's build (protocol 143)
| Room shape | Snapshots → joiner | Inputs → host | Headers | Out / relayed joiner | MB/min | MB/hour |
|---|---|---|---|---|---|---|
| 1v1 (2 fighters) | 13.4 KB/s | 4.0 | 2.5 | 19.9 KB/s | 1.20 | 72 |
| 4 fighters | 22.9 | 4.0 | 2.5 | 29.4 | 1.76 | 106 |
| 8 fighters | 27.3 | 4.0 | 2.5 | 33.8 | 2.03 | 122 |
Sources. The 1v1 rates are from the 3 Nov tester match report (build 1.0.0(7): host sent 13.12 KB/s, joiner 3.89 KB/s). The 4 and 8 fighter snapshot sizes come from the netsize labs (762 B and 904 B a snapshot, 19 % in two fragments). Headers are 28 B of IPv4 + UDP on each of 90 packets a second. Bots are fighters but not joiners: they make snapshots bigger but add no link.
Per player, both directions. In a relayed 1v1, each of the 2 players accounts for 0.60 MB/min out and 0.60 MB/min in, which is 1.2 MB/min, ~72 MB/hour. With a room mix of 60 % 1v1, 30 % 4-player and 10 % 8-player, a relayed room averages 1.16 MB/min out per player in it, which the cost table uses.
3 · What the VM can carry
bashatest is a Standard_B4as_v2 (4 vCPU AMD EPYC 7763v, 16 GiB) in India South Central (Hyderabad), zone 1, read from Azure's instance metadata. The relay runs in Docker as sbgame-relay-1 (image 785b6a8, host networking) with a 1-CPU, 256 MB cap. Its packet loop is single-threaded under one lock.
Limits, per relayed player
| Resource | Measured / spec | Per relayed player | Ceiling |
|---|---|---|---|
| CPU (the limit) | The 27 Oct load test on this VM: 0.10 % of a core per relayed 1v1 room at 90 packets/s (50 / 200 / 500 rooms: 7 / 22 / 50 % of a core). Full 8-player rooms: ~0.9 % of a core each. | 0.05 % (1v1) 0.11 % (8-player) | ~1,000 mixed 1,400 in 1v1s · 630 in 8-player rooms, at 70 % of the 1-CPU cap |
| Network | 6,250 Mbps NIC (accelerated networking: hv_netvsc + SR-IOV, 50 Gb link). | ~160 kbit/s out | ~39,000 (not a limit) |
| Memory | 7.7 MB RSS at 500 rooms; 5.6 MB idle now (cap 256 MB). | ~10 KB | not a limit |
| Relay's own caps | 2,000 confirmed rooms, 32 per IP (pending included), 400 packets/s and 200 KB/s per member (times the peers for a host). | - | 2,000 rooms |
| Burst credits | B4as_v2 runs at 40 % base (1.6 vCPU) and banks 96 credits an hour, up to 2,304. The VM averaged 37-63 % busy on 29 Oct - 3 Nov (sar), mostly labs and builds. | - | throttles the whole VM to 40 % when credits run out |
Reading. One relay CPU carries about 1,000 relayed players at once. Bandwidth isn't a concern until well past that. The real risk is the shared, burstable VM. Lab days spend more CPU than the base, so when credits run out the relay, sbapi and Postgres all slow down together. Before we promote online friends, move the labs off this VM or give the relay its own small non-burstable VM.
Egress already used. The VM sent 55.7 GB in 11.9 days (NIC counters), about 140 GB a month of non-game traffic (lab results, pushes, builds). That uses up Azure's free 100 GB, so every relay GB is billed from the first one while the VM is also the lab machine.
4 · Azure egress price for this region
India South Central is in Azure's "Asia (China excluded), Australia, MEA" bandwidth group. Incoming data is free.
Internet egress, per month
| Tier | Microsoft premium network (today) | Routing preference: Internet (ISP) |
|---|---|---|
| First 100 GB | free | free |
| Next 10 TB | $0.12 / GB | $0.11 / GB |
| Next 40 TB | $0.085 | $0.075 |
| Next 100 TB | $0.082 | $0.07 |
| Next 350 TB | $0.08 | $0.06 |
The spec's estimate used ~$0.10 / GB. The real first tier is $0.12, and every number below uses it. "Routing preference: Internet" would cut that by ~8 %, but it's a public-IP setting chosen when the IP is created, and it may add latency. Out of scope for this lane.
5 · Monthly cost per 1,000 daily players
Monthly relay GB = 1,000 × share playing online friend rooms × minutes a day × 30 × relay share × 1.16 MB. Priced at $0.12 / GB with no free tier left (section 3). ONLINE quick play and Wi-Fi parties never use the relay. Usage levels are guesses until launch numbers exist: light = 10 % of players, 15 min a day; typical = 20 %, 20 min; heavy = 40 %, 40 min.
$ / month per 1,000 daily players (GB in grey)
| Usage | 5 % relayed | 10 % | 25 % | 50 % | 100 % (worst) |
|---|---|---|---|---|---|
| Light 45k player-min | $0.31 2.6 | $0.63 5.2 | $1.57 13 | $3.14 26 | $6.28 52 |
| Typical 120k player-min | $0.84 7.0 | $1.68 14 | $4.19 35 | $8.38 70 | $16.76 140 |
| Heavy 480k player-min | $3.35 28 | $6.70 56 | $16.76 140 | $33.51 279 | $67.02 559 |
Reading. Relay cost grows with how much people play online friend rooms, not with installs. At typical use and a 10-25 % relay share it's about $2-4 a month per 1,000 daily players, so 100,000 daily players would be ~$170-420. A relayed player-hour costs $0.0084.
Around the clock: the cost of a busy relay
| Relayed players at once, all month | GB out / month | $ / month (tiered) |
|---|---|---|
| 20 (the spec's example: "~$50") | 1,005 | $121 |
| 100 | 5,027 | $603 |
| 300 | 15,081 | $1,632 |
| 1,000 (the VM's ceiling) | 50,269 | $4,622 |
The VM can carry far more relay traffic than we'd want to pay for. That's why the monthly budget is the guard that matters. The concurrent cap catches a sudden spike before the CPU does.
6 · Cap, budget, busy message
The build part, after APPROVED. The full sub-plan: stickbash-online docs/superpowers/plans/2026-11-03-prelaunch-relay.md. No relay redeploy: sbapi reads the relay's existing room log, which it already mounts read-only, and the host phone reports its relayed joiners.
Config keys (ops.relay, dashboard-editable)
ops.relay.capOnbool, default true. Off = never busy (the relay's own hard caps still apply).ops.relay.maxPlayersint 0-5000, default 300. Concurrent relayed players (a relayed 1v1 = 2). 0 = no new online rooms.ops.relay.monthlyBudgetGBint 0-100000, default 250 (≈ $30 a month at $0.12). Measured relay egress since the 1st, UTC.ops.relay.warnPctint 50-100, default 80. The dashboard tile turns orange at this share of the budget.ops.relay.busyMsgstring ≤ 80, default "" (the built-in words below).
What players see over the cap (concept)
ONLINE ROOM · KTQWZR
ROOMS BUSYROOM CODE sheet
ROOMS BUSY
PLAY ON WI-FI NOW · IT GOES ONLINE BY ITSELF SOON
Built 3 Nov (live-relaycap dd15e2d3d + stickbash-online live-relaycap a654722; wording per the coordinator 4 Nov 02:05): the room tag, its note and the ROOM CODE sheet as above. Only new online rooms wait. Rooms already open, and players already in them, carry on. The host's room stays a Wi-Fi room and retries every 60 s. When sbapi can't be reached the room opens as today (fail-open). The tag reuses the room's PAUSED tag style.
Dashboard readout (home tile + Numbers section)
RELAY tile: relayed players now / cap · GB this month / budget, with the $ so far and the month's projection · OPEN or BUSY (cap / budget). Numbers gets Relay share: the last 7 and 30 days of links, relayed links, link-minutes and relayed minutes, read from the relay's room log the same way as section 1.
Caveats
Small sample
12 shipping-build links, all Indian testers on 2-3 networks. The relay share at launch is unknown. Use the dashboard's daily share once real players arrive.
CPU is from 27 Oct
The load test ran relay build 4564b15 with 800 B snapshots. The deployed hardened relay (785b6a8) keeps 0 allocations a datagram. A fresh run on a private port is the sub-plan's optional task 0, never against the live relay.
Usage is a guess
The share of players in online friend rooms and their minutes are assumptions. Online friends are OFF in public builds today (Task 15). The cost lines scale linearly: double the minutes, double the dollars.
Sources: the live relay's events.jsonl + rooms-*.jsonl, telemetry events-2026-10-27 … 11-03.jsonl, matches*.jsonl (copied read-only from /srv/sbgame/relay), docker logs sbgame-relay-1 stats, /proc/net/dev, sar, Azure IMDS; stickbash-online docs/results/2026-10-27-load.md; StickFight Docs/Multiplayer.md (netsize). Prices: azure.microsoft.com/pricing/details/bandwidth; VM size: learn.microsoft.com … basv2-series (both read 3 Nov 2026).