Docs ▸ Steam
Steam
Your game gets window.steam in desktop builds and in play. It works with your own copy of Valve's Steamworks SDK; Gameshipper never ships Valve's files itself.
- Download the Steamworks SDK zip from https://partner.steamgames.com/downloads/list (you need a Steamworks partner login).
- Put it in your game folder's
.sdk/folder, e.g..sdk/steamworks_sdk_165.zip.initadds.sdk/to.gitignore: don't commit Valve's files. You can also setsteam.sdkin gameshipper.json (relative to the game folder), setGAMESHIPPER_STEAM_SDK, or pass--steam-sdk <path>. Once a build has used an SDK, Gameshipper keeps its libraries in its cache and later projects find them there. The SDK is never copied into the game, whatever it's called and wherever it is. npx gameshipper statusshows which SDK builds will use. Without one, builds still work (with aSTEAM_SDK_MISSINGwarning) andwindow.steam.isAvailable()resolvesfalse.
Each build gets only the Steam library its OS needs, copied from your SDK. Nobody needs a steam_appid.txt, and none is ever shipped.
if (window.steam && (await steam.isAvailable())) {
await steam.unlockAchievement('FIRST_WIN');
await steam.setStat('WINS', 10); // saved to Steam right away
await steam.uploadLeaderboardScore('HIGH_SCORES', 12345);
const top = await steam.getLeaderboardEntries('HIGH_SCORES', 10);
await steam.setRichPresence('status', 'Level 3');
const name = await steam.getUserName();
steam.activateOverlay('achievements');
}Every method resolves to a harmless value (false, null or []) when Steam isn't running, so the game never needs to guard each call. Also available: getSteamId, getLanguage, isSteamDeck, clearAchievement, isAchievementUnlocked, listAchievements, getStat, storeStats, clearRichPresence, activateOverlayWebPage, and GemShell-style names (getPersonaName, getSteamID, getAchievement, getStatInt, setStatInt, getStatFloat, setStatFloat, requestStats, requestStatsAndWait, runCallbacks), so GemShell games need few or no changes. Only the game's own pages can use window.steam. window.steam and window.gameshipper are ordinary globals: a game that has its own steam or gameshipper (a top-level const, let, var, function or class in a classic script, or window.steam = ...) keeps working, and its own takes the place of Gameshipper's.
- App ID.
steam.appIddefaults to 480, Valve's Spacewar test app, which every Steam account can use. With your own App ID, a packaged build started outside Steam asks Steam to launch it (Valve's standard check). - Overlay (Shift+Tab).
steam.overlayis"auto"by default. On macOS that uses a native window that mirrors the game so Steam's overlay can draw on it; on Windows and Linux it keeps a new frame coming 60 times a second. On macOS and Linux this happens only when Steam launched the game, which is when Steam injects its overlay. Set"native","repaint"or"off"to override.play --smokewarnsSTEAM_OVERLAY_FAILEDwhen the native window couldn't start. - Steam Deck. Steam's on-screen keyboard opens when a text field gets focus, and again when the player taps the field after closing it. Read-only fields get no keyboard.
- Quitting. The game waits up to a second for Steam calls still in flight (a leaderboard upload, say) before it disconnects from Steam.
- Troubleshooting.
play --smoke --jsonreportsSTEAM_NOT_RUNNING(a warning: start Steam) orSTEAM_INIT_FAILED(an error: usually an App ID the signed-in account doesn't own).