Stats Manager - ArtyProf/steamworks-ffi-node GitHub Wiki
Complete reference for all statistics-related functionality in Steamworks FFI.
The SteamStatsManager provides comprehensive Steam statistics tracking with 14 functions organized into logical categories.
| Category | Functions | Description |
|---|---|---|
| User Stats | 5 | Get/set integer and float stats, average rates |
| Friend/User Stats | 3 | Request and compare stats with friends |
| Global Stats | 5 | View aggregated stats across all users |
| Player Count | 1 | Get number of players currently playing |
Essential stat functionality for tracking and updating player statistics.
Get an integer stat value for the current user.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetStatInt32()- Get int32 stat value
Parameters:
-
statName: string- Name of the stat to retrieve
Returns: Promise<SteamStat | null> - SteamStat object with {name, value, type}, or null if not found
SteamStat Interface:
interface SteamStat {
name: string; // Stat name
value: number; // Stat value
type: 'int' | 'float'; // Data type
}Example:
import SteamworksSDK from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
steam.init({ appId: YOUR_APP_ID });
const killsStat = await steam.stats.getStatInt('total_kills');
if (killsStat) {
console.log(`${killsStat.name}: ${killsStat.value}`);
// Access value: killsStat.value
}
steam.shutdown();Get a float stat value for the current user.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetStatFloat()- Get float stat value
Parameters:
-
statName: string- Name of the stat to retrieve
Returns: Promise<SteamStat | null> - SteamStat object with {name, value, type}, or null if not found
Example:
const distanceStat = await steam.stats.getStatFloat('total_distance');
if (distanceStat) {
console.log(`${distanceStat.name}: ${distanceStat.value.toFixed(2)} km`);
}Set an integer stat value for the current user. Automatically stored to Steam servers.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_SetStatInt32()- Set int32 stat value -
SteamAPI_ISteamUserStats_StoreStats()- Store stats to Steam servers -
SteamAPI_RunCallbacks()- Process Steam callbacks
Parameters:
-
statName: string- Name of the stat to set -
value: number- Integer value to set
Returns: Promise<boolean> - true if successful
Example:
// Update kill count
const currentKills = await steam.stats.getStatInt('total_kills') || 0;
await steam.stats.setStatInt('total_kills', currentKills + 1);
// Track games played
const gamesPlayed = await steam.stats.getStatInt('games_played') || 0;
await steam.stats.setStatInt('games_played', gamesPlayed + 1);
// Set specific value
await steam.stats.setStatInt('player_level', 15);Note: Stats are automatically synced to Steam servers when set.
Set a float stat value for the current user. Automatically stored to Steam servers.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_SetStatFloat()- Set float stat value -
SteamAPI_ISteamUserStats_StoreStats()- Store stats to Steam servers -
SteamAPI_RunCallbacks()- Process Steam callbacks
Parameters:
-
statName: string- Name of the stat to set -
value: number- Float value to set
Returns: Promise<boolean> - true if successful
Example:
// Track distance traveled
const currentDistance = await steam.stats.getStatFloat('total_distance') || 0;
await steam.stats.setStatFloat('total_distance', currentDistance + 123.45);
// Track accuracy percentage
await steam.stats.setStatFloat('accuracy', 87.5);
// Track average speed
await steam.stats.setStatFloat('average_speed', 45.2);Update an average rate stat (e.g., kills per hour, damage per second). Steam automatically calculates the running average.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_UpdateAvgRateStat()- Update average rate stat -
SteamAPI_ISteamUserStats_StoreStats()- Store stats to Steam servers -
SteamAPI_RunCallbacks()- Process Steam callbacks
Parameters:
-
statName: string- Name of the stat to update -
countThisSession: number- Count for this session -
sessionLength: number- Length of session in seconds
Returns: Promise<boolean> - true if successful
Example:
// Player got 15 kills in 3600 seconds (1 hour)
await steam.stats.updateAvgRateStat('kills_per_hour', 15, 3600);
// Player dealt 500 damage in 60 seconds
await steam.stats.updateAvgRateStat('damage_per_second', 500, 60);
// Calculate session stats
const sessionStart = Date.now();
// ... gameplay happens ...
const sessionEnd = Date.now();
const sessionSeconds = (sessionEnd - sessionStart) / 1000;
await steam.stats.updateAvgRateStat('points_per_second', earnedPoints, sessionSeconds);Note: Steam maintains a running average across all sessions automatically.
Compare your stats with friends and other users.
Request stats for another user (friend). Must be called before getting user stats.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_RequestUserStats()- Request user stats from Steam
Parameters:
-
steamId: string | bigint- Steam ID of the user (e.g., "76561197960287930")
Returns: Promise<boolean> - true if request was sent successfully
Example:
const friendSteamId = '76561197960287930';
// Request friend's stats
await steam.stats.requestUserStatsForStats(friendSteamId);
// Wait for Steam to process the request
await new Promise(resolve => setTimeout(resolve, 2000));
steam.runCallbacks();
// Now you can get their stats
const friendKills = await steam.stats.getUserStatInt(friendSteamId, 'total_kills');Important:
- This is an asynchronous request
- Wait 1-2 seconds and call
runCallbacks()before retrieving stats - The friend must have played the game
Get an integer stat value for another user (friend). Must call requestUserStatsForStats() first.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetUserStatInt32()- Get user's int32 stat value
Parameters:
-
steamId: string | bigint- Steam ID of the user -
statName: string- Name of the stat to retrieve
Returns: Promise<UserStat | null> - UserStat object with {steamId, name, value, type}, or null if not found
UserStat Interface:
interface UserStat {
steamId: string; // User's Steam ID
name: string; // Stat name
value: number; // Stat value
type: 'int' | 'float'; // Data type
}Example:
async function compareWithFriend(friendSteamId: string) {
const steam = SteamworksSDK.getInstance();
steam.init({ appId: YOUR_APP_ID });
// Get your stats
const myKillsStat = await steam.stats.getStatInt('total_kills');
const myGamesStat = await steam.stats.getStatInt('games_played');
// Get friend's stats
await steam.stats.requestUserStatsForStats(friendSteamId);
await new Promise(resolve => setTimeout(resolve, 2000));
steam.runCallbacks();
const friendKills = await steam.stats.getUserStatInt(friendSteamId, 'total_kills');
const friendGames = await steam.stats.getUserStatInt(friendSteamId, 'games_played');
if (myKillsStat && myGamesStat && friendKills && friendGames) {
console.log('Comparison:');
console.log(`You: ${myKillsStat.value} kills in ${myGamesStat.value} games`);
console.log(`Friend: ${friendKills.value} kills in ${friendGames.value} games`);
console.log(`Difference: ${myKillsStat.value - friendKills.value} kills`);
}
steam.shutdown();
}Get a float stat value for another user (friend). Must call requestUserStatsForStats() first.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetUserStatFloat()- Get user's float stat value
Parameters:
-
steamId: string | bigint- Steam ID of the user -
statName: string- Name of the stat to retrieve
Returns: Promise<UserStat | null> - UserStat object with {steamId, name, value, type}, or null if not found
Example:
const friendDistance = await steam.stats.getUserStatFloat(friendSteamId, 'total_distance');
if (friendDistance) {
console.log(`${friendDistance.name}: ${friendDistance.value.toFixed(2)} km`);
}
const friendAccuracy = await steam.stats.getUserStatFloat(friendSteamId, 'accuracy');
if (friendAccuracy) {
console.log(`${friendAccuracy.name}: ${friendAccuracy.value.toFixed(1)}%`);
}View aggregated statistics across all users worldwide.
Request global stats data from Steam. Must be called before getting global stats.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_RequestGlobalStats()- Request global stats from Steam
Parameters:
-
historyDays: number(optional) - Number of days of history to retrieve (0-60, default: 0)
Returns: Promise<boolean> - true if request was sent successfully
Example:
// Request global stats without history
await steam.stats.requestGlobalStats(0);
// Request global stats with 7 days of history
await steam.stats.requestGlobalStats(7);
// Request global stats with maximum history (30 days)
await steam.stats.requestGlobalStats(30);
// Wait for Steam to process
await new Promise(resolve => setTimeout(resolve, 2000));
steam.runCallbacks();
// Now you can access global statsNote: Wait 2-3 seconds and call runCallbacks() before accessing global stats.
Get a global stat value (int64). Must call requestGlobalStats() first.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetGlobalStatInt64()- Get global int64 stat value
Parameters:
-
statName: string- Name of the global stat
Returns: Promise<GlobalStat | null> - GlobalStat object with {name, value, type: 'int64'}, or null if not found
GlobalStat Interface:
interface GlobalStat {
name: string; // Name of the stat
value: number; // Stat value (converted from BigInt)
type: 'int64' | 'double'; // Data type
}Example:
async function viewGlobalStats() {
const steam = SteamworksSDK.getInstance();
steam.init({ appId: YOUR_APP_ID });
// Request global stats
await steam.stats.requestGlobalStats(0);
await new Promise(resolve => setTimeout(resolve, 2000));
steam.runCallbacks();
// Get aggregated stats
const totalPlayers = await steam.stats.getGlobalStatInt('global.total_players');
const totalKills = await steam.stats.getGlobalStatInt('global.total_kills');
const totalGames = await steam.stats.getGlobalStatInt('global.games_played');
if (totalPlayers && totalKills && totalGames) {
console.log('š Global Statistics:');
console.log(`Total Players: ${totalPlayers.value}`);
console.log(`Total Kills: ${totalKills.value}`);
console.log(`Total Games: ${totalGames.value}`);
const avgKillsPerPlayer = totalKills.value / totalPlayers.value;
console.log(`Average Kills per Player: ${avgKillsPerPlayer.toFixed(2)}`);
}
steam.shutdown();
}Get a global stat value (double). Must call requestGlobalStats() first.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetGlobalStatDouble()- Get global double stat value
Parameters:
-
statName: string- Name of the global stat
Returns: Promise<GlobalStat | null> - GlobalStat object with {name, value, type: 'double'}, or null if not found
Example:
const totalDistance = await steam.stats.getGlobalStatDouble('global.total_distance');
if (totalDistance) {
console.log(`Total distance traveled by all players: ${totalDistance.value} km`);
}
const avgAccuracy = await steam.stats.getGlobalStatDouble('global.average_accuracy');
if (avgAccuracy) {
console.log(`Global average accuracy: ${avgAccuracy.value.toFixed(2)}%`);
}Get historical data for a global stat (int64). Returns daily values.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetGlobalStatHistoryInt64()- Get global stat history
Parameters:
-
statName: string- Name of the global stat -
days: number(optional) - Number of days of history (1-60, default: 7)
Returns: Promise<GlobalStatHistory | null> - GlobalStatHistory object with {name, history, type: 'int64'}, or null if not found
GlobalStatHistory Interface:
interface GlobalStatHistory {
name: string; // Name of the stat
history: number[]; // Array of daily values (converted from BigInt)
type: 'int64' | 'double'; // Data type
}Example:
const historyData = await steam.stats.getGlobalStatHistoryInt('global.daily_kills', 7);
if (historyData) {
console.log('Last 7 days of global kills:');
historyData.history.forEach((kills, index) => {
const label = index === 0 ? 'Today' :
index === 1 ? 'Yesterday' :
`${index} days ago`;
console.log(`${label}: ${kills} kills`);
});
// Calculate trend
const total = historyData.history.reduce((sum, val) => sum + val, 0);
const average = total / historyData.history.length;
console.log(`7-day average: ${average.toFixed(2)} kills/day`);
}Get historical data for a global stat (double). Returns daily values.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetGlobalStatHistoryDouble()- Get global stat history
Parameters:
-
statName: string- Name of the global stat -
days: number(optional) - Number of days of history (1-60, default: 7)
Returns: Promise<GlobalStatHistory | null> - GlobalStatHistory object with {name, history, type: 'double'}, or null if not found
Example:
const playtimeData = await steam.stats.getGlobalStatHistoryDouble('global.daily_playtime', 30);
if (playtimeData) {
console.log('Last 30 days of global playtime:');
const totalHours = playtimeData.history.reduce((sum, hours) => sum + hours, 0);
const avgHoursPerDay = totalHours / playtimeData.history.length;
console.log(`Total: ${totalHours} hours`);
console.log(`Average: ${avgHoursPerDay.toFixed(2)} hours/day`);
// Find peak day
const maxHours = Math.max(...playtimeData.history);
const peakIndex = playtimeData.history.indexOf(maxHours);
console.log(`Peak day: ${peakIndex} days ago with ${maxHours.toFixed(2)} hours`);
}Before using stats, configure them in your Steamworks Partner account:
-
Go to Stats & Achievements
- Navigate to your app's Stats & Achievements section
- Click on "Stats" tab
-
Add Stat Definitions
- Click "Add New Stat"
- Set stat name (e.g., "total_kills", "games_played")
- Choose type: Integer (int32) or Float
- Set default value (usually 0)
-
Configure Global Stats (optional)
- Check "Aggregated" to enable global statistics
- This allows
getGlobalStat*functions to work
-
Set Display Properties (optional)
- Display name: User-friendly name
- Increment only: Prevents stat from decreasing
- Max change: Maximum allowed change per update
-
Publish Changes
- Click "Publish" to make stats available
- Changes may take a few minutes to propagate
interface SteamStat {
name: string;
value: number;
type: 'int' | 'float';
}
interface UserStat {
steamId: string;
name: string;
value: number;
type: 'int' | 'float';
}
interface GlobalStat {
name: string;
value: number;
type: 'int64' | 'double';
}
interface GlobalStatHistory {
name: string;
history: number[]; // [0] = today, [1] = yesterday, etc.
type: 'int64' | 'double';
}import SteamworksSDK from 'steamworks-ffi-node';
async function trackGameSession() {
const steam = SteamworksSDK.getInstance();
steam.init({ appId: YOUR_APP_ID });
// Session start
const sessionStart = Date.now();
// Get current stats
const gamesPlayedStat = await steam.stats.getStatInt('games_played');
const totalKillsStat = await steam.stats.getStatInt('total_kills');
const totalDistanceStat = await steam.stats.getStatFloat('total_distance');
const gamesPlayed = gamesPlayedStat ? gamesPlayedStat.value : 0;
const totalKills = totalKillsStat ? totalKillsStat.value : 0;
const totalDistance = totalDistanceStat ? totalDistanceStat.value : 0;
// Simulate gameplay
const sessionKills = 15;
const sessionDistance = 1234.56;
// Update stats
await steam.stats.setStatInt('games_played', gamesPlayed + 1);
await steam.stats.setStatInt('total_kills', totalKills + sessionKills);
await steam.stats.setStatFloat('total_distance', totalDistance + sessionDistance);
// Update average rate stats
const sessionEnd = Date.now();
const sessionSeconds = (sessionEnd - sessionStart) / 1000;
await steam.stats.updateAvgRateStat('kills_per_hour', sessionKills, sessionSeconds);
console.log('ā
Session stats saved to Steam');
steam.shutdown();
}
trackGameSession();async function createLeaderboard(friendSteamIds: string[]) {
const steam = SteamworksSDK.getInstance();
steam.init({ appId: YOUR_APP_ID });
// Get your stats
const myKillsStat = await steam.stats.getStatInt('total_kills');
const myGamesStat = await steam.stats.getStatInt('games_played');
const myKills = myKillsStat ? myKillsStat.value : 0;
const myGames = myGamesStat ? myGamesStat.value : 0;
const myKDR = myGames > 0 ? myKills / myGames : 0;
const leaderboard = [
{ name: 'You', kills: myKills, games: myGames, kdr: myKDR }
];
// Get friends' stats
for (const friendId of friendSteamIds) {
await steam.stats.requestUserStatsForStats(friendId);
await new Promise(resolve => setTimeout(resolve, 2000));
steam.runCallbacks();
const friendKillsStat = await steam.stats.getUserStatInt(friendId, 'total_kills');
const friendGamesStat = await steam.stats.getUserStatInt(friendId, 'games_played');
const friendKills = friendKillsStat ? friendKillsStat.value : 0;
const friendGames = friendGamesStat ? friendGamesStat.value : 0;
const friendKDR = friendGames > 0 ? friendKills / friendGames : 0;
leaderboard.push({
name: `Friend ${friendId.slice(-4)}`,
kills: friendKills,
games: friendGames,
kdr: friendKDR
});
}
// Sort by kills
leaderboard.sort((a, b) => b.kills - a.kills);
// Display leaderboard
console.log('\nš Leaderboard:');
leaderboard.forEach((player, index) => {
console.log(`${index + 1}. ${player.name}`);
console.log(` Kills: ${player.kills}, Games: ${player.games}, KDR: ${player.kdr.toFixed(2)}`);
});
steam.shutdown();
}async function showGlobalDashboard() {
const steam = SteamworksSDK.getInstance();
steam.init({ appId: YOUR_APP_ID });
// Request global stats with 30 days history
await steam.stats.requestGlobalStats(30);
await new Promise(resolve => setTimeout(resolve, 2000));
steam.runCallbacks();
console.log('\nš GLOBAL STATISTICS DASHBOARD\n');
// Overall stats
const totalPlayers = await steam.stats.getGlobalStatInt('global.total_players');
const totalKills = await steam.stats.getGlobalStatInt('global.total_kills');
const totalGames = await steam.stats.getGlobalStatInt('global.games_played');
if (totalPlayers && totalKills && totalGames) {
console.log('š Overall Statistics:');
console.log(`Players: ${totalPlayers.value}`);
console.log(`Total Kills: ${totalKills.value}`);
console.log(`Total Games: ${totalGames.value}`);
console.log(`Avg Kills/Player: ${(totalKills.value / totalPlayers.value).toFixed(2)}\n`);
}
// Historical trends
const killHistoryData = await steam.stats.getGlobalStatHistoryInt('global.daily_kills', 7);
if (killHistoryData) {
console.log('š Last 7 Days Trend:');
killHistoryData.history.forEach((kills, index) => {
const day = index === 0 ? 'Today' : index === 1 ? 'Yesterday' : `${index}d ago`;
const bar = 'ā'.repeat(Math.floor(kills / 10000));
console.log(`${day.padEnd(10)} ${kills.toString().padStart(10)} ${bar}`);
});
}
steam.shutdown();
}Stats may not be configured or available:
const killsStat = await steam.stats.getStatInt('total_kills');
if (killsStat) {
console.log(`Kills: ${killsStat.value}`);
} else {
console.log('Stat not configured in Steamworks');
}- int32: Whole numbers (kills, games, levels)
- float: Decimals (distance, accuracy, speed)
- Average rates: Time-based averages (kills/hour, DPS)
Always wait for Steam callbacks:
// ā Wrong
await steam.stats.requestGlobalStats(7);
const stat = await steam.stats.getGlobalStatInt('global.kills'); // null!
// ā
Correct
await steam.stats.requestGlobalStats(7);
await new Promise(resolve => setTimeout(resolve, 2000));
steam.runCallbacks();
const stat = await steam.stats.getGlobalStatInt('global.kills'); // works!Update multiple stats together for efficiency:
// Update all session stats at once
await steam.stats.setStatInt('games_played', gamesPlayed + 1);
await steam.stats.setStatInt('total_kills', totalKills + sessionKills);
await steam.stats.setStatFloat('total_distance', totalDistance + sessionDistance);
await steam.stats.updateAvgRateStat('kills_per_hour', sessionKills, sessionSeconds);All getter methods return typed objects with metadata:
const killsStat = await steam.stats.getGlobalStatInt('global.total_kills');
if (killsStat) {
// Access the value
console.log(`Total: ${killsStat.value}`);
// Access metadata
console.log(`Stat name: ${killsStat.name}`);
console.log(`Data type: ${killsStat.type}`); // 'int64'
}All stat methods return null or false on error and log warnings:
// Returns null on error
const stat = await steam.stats.getStatInt('invalid_stat');
if (stat === null) {
console.log('Stat not found - check Steamworks configuration');
}
// Returns false on error
const success = await steam.stats.setStatInt('my_stat', 100);
if (!success) {
console.log('Failed to set stat - check initialization');
}Common Issues:
ā ļø Stat not configured: Add stat in Steamworks Partner siteā ļø Steam not initialized: Callsteam.init()before using statsā ļø Async not complete: Wait longer and callrunCallbacks()ā ļø Friend stats unavailable: Friend must have played the gameā ļø Global stats not configured: Mark stats as "aggregated" in Steamworks
Get information about how many players are currently playing the game.
Get the total number of players currently playing the game globally (online + offline).
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetNumberOfCurrentPlayers()- Request current player count -
ISteamUtils::IsAPICallCompleted()- Check if callback completed -
ISteamUtils::GetAPICallResult()- Retrieve callback result
Parameters: None
Returns: Promise<number | null> - Number of current players, or null on error
Example:
const playerCount = await steam.stats.getNumberOfCurrentPlayers();
if (playerCount !== null) {
console.log(`š® ${playerCount.toLocaleString()} players currently playing!`);
// Use in UI
document.getElementById('playerCount').textContent =
`${playerCount.toLocaleString()} players online`;
}Advanced Usage:
// Poll periodically for live updates
setInterval(async () => {
const count = await steam.stats.getNumberOfCurrentPlayers();
if (count !== null) {
console.log(`Current players: ${count}`);
}
}, 60000); // Update every minuteImportant Notes:
- ā Queries Steam servers and waits for response (typically 50-500ms)
- ā Includes both online and offline players
- ā Useful for displaying "X players online" in game UI
- ā Data is cached by Steam for a short period to reduce server load
- ā Uses callback polling to get actual results synchronously
Callback: NumberOfCurrentPlayers_t
-
m_bSuccess- Whether the request was successful (0 or 1) -
m_cPlayers- Number of players currently playing