A lean TypeScript Steam client for Node.js. It handles the low-level CM connection, authentication, and message framing — giving you a clean foundation to build Steam integrations on top of.
- Full TypeScript API with typed Steam protos
- QR code and credential login flows (with Steam Guard support)
- Logon via refresh token
- WebSocket transport to Steam CM servers
- HTTP, HTTPS, and SOCKS5 proxy support
- Node.js
>= 22 - npm
>= 9.5.1
npm install @steamlab/steam-clientimport { SteamClient } from "@steamlab/steam-client";
import type { ConnectionOptions } from "@steamlab/steam-client";
const options: ConnectionOptions = {
steamCM: { host: "cmp1-iad1.steamserver.net", port: 27018 },
timeout: 15_000,
};
const client = new SteamClient(options);
client.emitter.on("disconnected", (msg) => {
console.log("Disconnected:", msg);
});
await client.connect();The authentication-qr event fires with a challengeUrl. Render the QR code however you like — the client polls Steam in the background and resolves once the user scans it.
client.emitter.once("authentication-qr", ({ challengeUrl }) => {
// Render challengeUrl as a QR code in your UI
console.log(challengeUrl);
});
client.emitter.once("steam-auth-tokens", ({ tokens }) => {
console.log("Refresh token:", tokens.refreshToken);
console.log("Access token:", tokens.accessToken);
});
await client.services.authentication.loginViaQr();Credential login is a two-step flow. Pass a Promise<string> as the second argument so the client can await a Steam Guard code if Steam requests one during sign-in. Resolve it with the device or email code when it becomes available.
// Listen for the type of guard required
client.emitter.on("authentication-2fa-required", ({ guardType }) => {
// guardType: "device_code" | "email_code" | "device_confirmation" | "email_confirmation"
console.log("Steam Guard required:", guardType);
});
client.emitter.once("steam-auth-tokens", ({ tokens }) => {
console.log("Refresh token:", tokens.refreshToken);
console.log("Access token:", tokens.accessToken);
});
// Use a promise to bridge the guard code from wherever it arrives
const { promise: codePromise, resolve: resolveCode } = Promise.withResolvers<string>();
const logonPromise = client.services.authentication.loginViaCredentials(
{ account_name: "your-username", password: "your-password" },
codePromise,
);
// Supply the code when it arrives (e.g. from user input or your own service)
resolveCode("AB123");
await logonPromise;Device and email confirmation types do not require a code — just approve the sign-in notification when it arrives in the Steam app or email.
If you already have a valid refresh token from a previous session, you can skip the full auth flow:
await client.logonRequest({ access_token: refreshToken });All options are passed to the SteamClient constructor.
| Option | Type | Required | Description |
|---|---|---|---|
steamCM.host |
string |
Yes | CM server hostname |
steamCM.port |
number |
Yes | CM server port |
timeout |
number |
Yes | Connection timeout in milliseconds |
proxy |
ProxyConfiguration |
No | HTTP, HTTPS, or SOCKS5 proxy |
import type { ConnectionOptions } from "@steamlab/steam-client";
const options: ConnectionOptions = {
steamCM: { host: "cmp1-iad1.steamserver.net", port: 27018 },
timeout: 10_000,
proxy: {
protocol: "socks5",
host: "127.0.0.1",
port: 1080,
username: "user", // optional
password: "pass", // optional
},
};| Method | Description |
|---|---|
client.connect() |
Connects to the Steam CM server |
client.disconnect() |
Disconnects from the CM server |
client.logonRequest(payload) |
Logs on using a refresh token |
client.startPlaying(gameId) |
Reports a game as being played. Accepts bigint, number, string, or arrays of those values |
client.stopPlaying(gameId) |
Stops reporting a game as being played. Accepts bigint, number, string, or arrays of those values |
Services are available via client.services.
| Service | Description |
|---|---|
client.services.authentication |
QR and credential login flows |
client.services.player |
Player-related Steam service calls. GetOwnedGames() is implemented; many generated player methods are not implemented yet |
At the moment, client.services.player.GetOwnedGames() is the main ready-to-use player helper:
const ownedGames = await client.services.player.GetOwnedGames();
console.log(ownedGames.games);Listen to events via client.emitter.
| Event | Payload | Description |
|---|---|---|
disconnected |
DisconnectMsg |
Fired when the connection drops |
authentication-qr |
{ challengeUrl: string } |
QR login URL ready to render |
authentication-2fa-required |
{ guardType: SteamGuardType } |
Steam Guard code or confirmation needed |
steam-auth-tokens |
{ tokens: SteamAuthTokens } |
Auth tokens received after login |
import {
SteamClient,
ProtoManager,
EMsg,
EResult,
SteamEnums,
ConnectionError,
SteamClientError,
SteamProtocolError,
SteamProtocolEResultError,
} from "@steamlab/steam-client";ISC — © steamlab-dev