Skip to content

Steam Events ​

Some things do not happen because your game asked. A friend accepts an invite, a player clicks "Join Game" in their friends list, another player opens a direct connection, a DLC finishes installing. Steam raises those on its own, and this is how the game hears about them.

Two calls: pollEvents() lets Steam hand over whatever it has been holding and says whether anything is waiting, and popEvent() takes the oldest one. Call them from a loop or a timer.

Events are kept until you fetch them, up to 256. Past that the oldest go first, so a game that polls now and then still sees what is happening now.

Methods ​

pollEvents() ​

Lets Steam deliver, and says whether anything is waiting.

javascript
if (await steam.pollEvents()) {
  // something arrived
}

popEvent() ​

The oldest event, or null when there is none.

javascript
let event;
while ((event = await steam.popEvent())) {
  console.log(event.type, event);
}

The events ​

typeFieldsWhat happened
overlayActivatedactiveThe Steam overlay opened or closed
lobbyJoinRequestedlobbyId, friendIdThe player accepted an invite from their friends list
richPresenceJoinRequestedfriendId, connectThe same, through your rich presence connect string
p2pSessionRequeststeamIdAnother player wants a direct connection
dlcInstalledappIdA DLC finished installing while the game was running
inventoryResultReadyhandle, resultAn inventory call finished
inventoryFullUpdatehandleThe player's inventory changed
musicPlaybackStatusChanged—Steam Music started, stopped or paused
musicVolumeChangedvolumeThe player changed the Steam Music volume
parentalSettingsChanged—Family View was changed while the game was running

Steam ids and lobby ids arrive as decimal strings, because they are 64-bit numbers and JavaScript cannot hold those exactly.

Examples ​

One pump, in the game loop ​

javascript
async function pumpSteam() {
  if (!(await steam.pollEvents())) return;
  let e;
  while ((e = await steam.popEvent())) {
    switch (e.type) {
      case 'lobbyJoinRequested':
        await steam.joinLobby(e.lobbyId);
        break;
      case 'p2pSessionRequest':
        await steam.acceptP2PSessionWithUser(e.steamId);
        break;
      case 'overlayActivated':
        if (e.active) pauseGame();
        break;
    }
  }
}

setInterval(pumpSteam, 100);

Joining from the friends list ​

A player who clicks "Join Game" on a friend gets one of two events, depending on whether the friend's game published a lobby or a connect string. Handle both and the button works either way.

javascript
case 'lobbyJoinRequested':
  await steam.joinLobby(e.lobbyId);
  break;

case 'richPresenceJoinRequested':
  // whatever you put in the 'connect' rich presence key
  const params = new URLSearchParams(e.connect);
  await joinServer(params.get('host'));
  break;

Waiting for a DLC ​

javascript
case 'dlcInstalled':
  if (e.appId === MY_EXPANSION_APPID) {
    await unlockExpansionContent();
    showToast('Expansion installed');
  }
  break;

Notes ​

  • Polling costs almost nothing when there is nothing waiting. Once or twice a second is plenty for invites; every frame is fine too.
  • The overlay also has its own callback, overlay.onStateChange(), which is usually easier than watching for overlayActivated.
  • Events need Steam running and init() to have succeeded. Without Steam, pollEvents() answers false for ever and nothing else happens.