Hasan Alp Güngör
All posts

· Hasan Alp Güngör

A Major-style live broadcast overlay for CS2 with Game State Integration

How I get live match data out of Counter-Strike 2 with Game State Integration, the Python server in between, and how I work out the killfeed the game doesn't send.

Watching Major tournaments, the broadcast overlay always caught my eye: every player's health, money and weapons, the killfeed, the bomb timer. I wanted to build something like it for my own matches.

Getting data out of the game

CS2 has a feature called Game State Integration (GSI). You put a file in the game's cfg folder, and during a match the game sends the data you asked for as JSON to the address you gave it. Mine asks for updates every 0.1 seconds, sent to a local server:

cfg"Manyaksisko35 GSI v1"
{
 "uri" "http://127.0.0.1:3000"
 "throttle" "0.1"
 "data"
 {
   "map"                    "1"
   "round"                  "1"
   "player_state"           "1"
   "allplayers_state"       "1"
   "allplayers_weapons"     "1"
   "allplayers_match_stats" "1"
   "phase_countdowns"       "1"
 }
}

A Python server in between

The JSON the game sends is big and messy. A small Flask server I wrote in Python takes it and boils it down: scores, the round, the bomb state, the time left, and for every player their name, health, money, main weapon, grenades and K/D. To find the main weapon I skip the knife, the C4 and the pistol, and fall back to the pistol if there's nothing else. The overlay pulls this clean data from a separate address.

An overlay that doesn't flicker

The overlay is HTML, CSS and JavaScript, and it pulls from the server 10 times a second. My first version redrew every panel each time and it flickered on stream. Now each field only updates when its value actually changes, and the health bars slide smoothly with a CSS transition.

The killfeed the game doesn't send

GSI doesn't say who killed whom. So on every update I compare each player's kills and deaths with the previous state. Players whose kills went up are the killers, players whose deaths went up are the victims; I pair them up and add them to the killfeed with the weapon icon. Each line fades out after five seconds.

jsplayers.forEach((p) => {
  const before = previous[p.name];
  if (before && p.kills > before.kills) killers.push(p);
  if (before && p.deaths > before.deaths) victims.push(p);
});
for (let i = 0; i < Math.max(killers.length, victims.length); i++) {
  addKillItem(killers[i], victims[i]);
}

The bomb timer

When the bomb is planted, the round timer gives way to a 40-second red bomb bar. When a defuse starts, the bar turns white. The game doesn't say how long the defuse takes, so I look at the time left: under 5.5 seconds means the player has a kit and the bar runs over 5 seconds, otherwise over 10.

The code is open on GitHub, and I also walked through building it on my YouTube channel.

Project pageCS2 Major HUDGame broadcast overlay

More posts