The SteamAPICore module manages the Steam API lifecycle, including initialization, shutdown, and callback processing. It serves as the foundation for all Steam operations in the modular steamworks-ffi-node architecture.
SteamAPICore is responsible for:
- Ensuring application was launched through Steam (
restartAppIfNecessary) - Initializing the Steam API connection
- Managing Steam interface handles (UserStats, User)
- Processing Steam callbacks
- Checking Steam client status
- Shutting down the Steam API cleanly
Set custom SDK path (optional).
Must be called BEFORE restartAppIfNecessary() or init() if using a custom SDK location.
The path should be relative to the project root.
Parameters:
customSdkPath(string) - Path to the steamworks_sdk folder (e.g., 'vendor/steamworks_sdk')
Example:
import SteamworksSDK from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
// IMPORTANT: Set SDK path BEFORE any Steam operations
steam.setSdkPath('vendor/steamworks_sdk');
// Now restartAppIfNecessary() will use the custom path
if (steam.restartAppIfNecessary(480)) {
process.exit(0);
}
steam.init({ appId: 480 });Custom SDK Path Examples:
// Vendor folder organization
steam.setSdkPath('vendor/steamworks_sdk');
// Nested SDK structure
steam.setSdkPath('libs/sdk/steamworks');
// Monorepo configuration
steam.setSdkPath('packages/game/steamworks_sdk');Enable or disable debug logging.
Controls debug output for Steam API operations. When enabled, displays detailed information about SDK loading, initialization, and internal operations. Errors and warnings are always shown regardless of debug mode.
Must be called BEFORE restartAppIfNecessary() or init() to see early initialization logs.
Parameters:
enabled(boolean) -trueto enable debug logs,falseto disable (default: false)
Example:
import SteamworksSDK from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
// Enable debug mode to see detailed logs
steam.setDebug(true);
// Set custom SDK path (debug logs will show path resolution)
steam.setSdkPath('vendor/steamworks_sdk');
// Check restart requirement (debug logs will show library loading)
if (steam.restartAppIfNecessary(480)) {
process.exit(0);
}
// Initialize (debug logs will show initialization steps)
steam.init({ appId: 480 });
// Disable debug logs after initialization if desired
steam.setDebug(false);What it does:
- Controls visibility of debug-level log messages
- Shows SDK path resolution and library loading details
- Displays initialization steps and interface setup
- Shows shutdown progress
- Always displays errors and warnings regardless of debug setting
Benefits:
- Development: See detailed initialization and SDK loading information
- Production: Disable debug logs to reduce noise
- Troubleshooting: Diagnose SDK path issues and initialization problems
- Flexibility: Toggle at any point during runtime
Debug Log Examples:
[Steamworks] Debug mode enabled
[Steamworks] Using custom SDK path: vendor/steamworks_sdk
[Steamworks] Loading Steamworks SDK from: /path/to/vendor/steamworks_sdk/redistributable_bin/osx/libsteam_api.dylib
[Steamworks] Initializing Steam API...
[Steamworks] Requesting current stats from Steam...
[Steamworks] Steam API initialized successfully!
[Steamworks] Connected to Steam for App ID: 480
Initialize the Steam API and connect to the Steam client.
Steamworks SDK Functions:
SteamAPI_Init()- Initialize Steam APISteamAPI_SteamUserStats_v013()- Get UserStats interfaceSteamAPI_SteamUser_v023()- Get User interfaceSteamAPI_ISteamUserStats_RequestCurrentStats()- Request current statsSteamAPI_IsSteamRunning()- Check Steam client statusSteamAPI_ISteamUser_GetSteamID()- Get user's Steam ID
Parameters:
interface SteamInitOptions {
appId: number; // Your Steam Application ID
}Returns: boolean - true if initialization successful, false otherwise
Example:
import SteamworksSDK from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
// Default SDK location (steamworks_sdk/ in project root)
const success = steam.init({ appId: 480 });
if (success) {
console.log('✅ Connected to Steam!');
} else {
console.error('❌ Failed to connect to Steam');
}With Custom SDK Path:
const steam = SteamworksSDK.getInstance();
// Set custom SDK path BEFORE init()
steam.setSdkPath('vendor/steamworks_sdk');
// Ensure app launched through Steam
if (steam.restartAppIfNecessary(480)) {
process.exit(0);
}
// Now initialize with custom SDK location
const success = steam.init({ appId: 480 });What it does:
- Sets
SteamAppIdenvironment variable - Loads the Steamworks SDK library via FFI from custom path (if set via setSdkPath()) or default locations
- Calls
SteamAPI_Init()to connect to Steam client - Retrieves interface handles for UserStats and User
- Requests current stats from Steam servers via
RequestCurrentStats() - Processes initial Steam callbacks
Requirements:
- Steam client must be running
- User must be logged in
- Valid Steam App ID
Shutdown the Steam API connection and clean up resources.
Steamworks SDK Functions:
SteamAPI_Shutdown()- Disconnect from Steam
Example:
steam.shutdown();
console.log('Steam API disconnected');What it does:
- Calls
SteamAPI_Shutdown()to disconnect - Cleans up interface handles
- Resets initialization state
Best Practice:
Always call shutdown() before your application exits:
process.on('exit', () => {
steam.shutdown();
});
process.on('SIGINT', () => {
steam.shutdown();
process.exit(0);
});Get current Steam API status and user information.
Steamworks SDK Functions:
SteamAPI_ISteamUser_GetSteamID()- Get user's Steam ID
Returns:
interface SteamStatus {
initialized: boolean; // Whether API is initialized
appId: number; // Current Steam App ID
steamId: string; // User's Steam ID (64-bit as string)
}Example:
const status = steam.getStatus();
console.log(`Connected: ${status.initialized}`);
console.log(`App ID: ${status.appId}`);
console.log(`Steam ID: ${status.steamId}`);Process pending Steam callbacks. Should be called regularly.
Steamworks SDK Functions:
SteamAPI_RunCallbacks()- Process all pending callbacks
Example:
// Process callbacks after operations
await steam.unlockAchievement('ACH_WIN_ONE_GAME');
steam.runCallbacks(); // Process the achievement unlock callback
// Or in a game loop
setInterval(() => {
steam.runCallbacks();
}, 1000); // Every secondWhat it does: Processes pending Steam callbacks such as:
- Achievement unlock confirmations
- Stats update confirmations
- User stats received callbacks
- Global stats received callbacks
Best Practice: Call after Steam operations that trigger callbacks:
// After unlocking achievement
await steam.unlockAchievement('ACH_WIN_ONE_GAME');
steam.runCallbacks();
// After requesting global stats
await steam.requestGlobalAchievementPercentages();
await new Promise(resolve => setTimeout(resolve, 2000));
steam.runCallbacks(); // Process the callbackCheck if Steam client is currently running.
Steamworks SDK Functions:
SteamAPI_IsSteamRunning()- Check Steam client status
Returns: boolean - true if Steam is running, false otherwise
Example:
if (!steam.isSteamRunning()) {
console.error('❌ Steam client is not running');
console.log('💡 Please start Steam and try again');
process.exit(1);
}Use Case: Check before initialization:
if (steam.isSteamRunning()) {
const success = steam.init({ appId: 480 });
} else {
console.error('Please launch Steam first');
}Ensures your application was launched through the Steam client. If not, Steam will restart your application properly and this function returns true, indicating your app should exit immediately.
Steamworks SDK Functions:
SteamAPI_RestartAppIfNecessary()- Check if app needs to restart through Steam
Parameters:
appId(number) - Your Steam Application ID
Returns:
true- App should terminate immediately (Steam is restarting it)false- App should continue normally (launched correctly)
When to Use:
Call this before init() to ensure your application:
- Was launched through Steam client
- Has proper Steam overlay support
- Has correct Steam authentication
Example - Basic Usage:
import SteamworksSDK from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
// Check BEFORE initializing
if (steam.restartAppIfNecessary(480)) {
console.log('App was not launched through Steam. Restarting...');
process.exit(0);
}
// If we reach here, continue with normal initialization
steam.init({ appId: 480 });Example - Electron Integration:
import { app } from 'electron';
import SteamworksSDK from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
app.whenReady().then(() => {
// Check before doing anything else
if (steam.restartAppIfNecessary(480)) {
console.log('Restarting through Steam...');
app.quit();
return;
}
// Continue with normal initialization
steam.init({ appId: 480 });
// ... rest of app initialization
createWindow();
});Example - Express/Node.js Server:
import express from 'express';
import SteamworksSDK from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
// Check at startup
if (steam.restartAppIfNecessary(480)) {
console.log('Server needs to restart through Steam');
process.exit(0);
}
steam.init({ appId: 480 });
const app = express();
// ... server setupHow It Works:
Returns false (continue normally) when:
- ✅ App was launched through Steam client
- ✅
steam_appid.txtfile exists (development mode) - ✅
SteamAppIdenvironment variable is set (development mode) - ✅ Steam is not installed (safe fallback)
Returns true (should exit) when:
- ❌ App was launched directly by user (not through Steam)
- ❌ No development files/env vars present
- ❌ Steam client detects improper launch
What Happens When It Returns True:
- User double-clicked your
.exeinstead of launching through Steam - Function returns
true - Your app calls
process.exit(0) - Steam client detects this and launches your app properly
- On relaunch, function returns
falseand app continues normally
Development Mode:
You don't need Steam launch during development! Use either:
Option 1: steam_appid.txt file
echo "480" > steam_appid.txtOption 2: Environment variable
export SteamAppId=480
node your-app.jsOption 3: Skip check in development
const isDevelopment = process.env.NODE_ENV === 'development';
if (!isDevelopment && steam.restartAppIfNecessary(480)) {
process.exit(0);
}
steam.init({ appId: 480 });Production Deployment:
For production releases on Steam:
- Always call this before
init()- Ensures proper Steam integration - Don't include
steam_appid.txt- Only for development - Steam DRM users can skip - DRM wrapper handles this automatically
- Test both scenarios:
- Launch through Steam (should continue normally)
- Launch
.exedirectly (should restart through Steam)
When NOT Needed:
- ❌ Using Steam DRM wrapper on your executable
- ❌ Development/testing with
steam_appid.txtor env var - ❌ App is not distributed through Steam
Best Practices:
✅ DO:
- Call before
init()for best results - Exit immediately if it returns
true - Use during production builds
- Test both launch methods
❌ DON'T:
- Call after
init()(too late) - Ignore the return value
- Include
steam_appid.txtin production - Skip this for Steam-distributed apps (unless using DRM)
Troubleshooting:
Problem: Always returns true even when launched through Steam
- ✅ Solution: Remove
steam_appid.txtfrom production build - ✅ Solution: Ensure you're testing with the actual Steam build
Problem: Returns false but overlay doesn't work
- ✅ Solution: Call this BEFORE
init(), not after - ✅ Solution: Verify Steam overlay is enabled in Steam settings
Problem: Can't test during development
- ✅ Solution: Create
steam_appid.txtwith your App ID - ✅ Solution: Set
SteamAppIdenvironment variable
See Also:
Get the current language that Steam is running in. This is useful for loading appropriate localization files for your game.
Steamworks SDK Functions:
SteamAPI_SteamApps_v008()- Get Apps interfaceSteamAPI_ISteamApps_GetCurrentGameLanguage()- Get current language
Returns: string - Language code (e.g., 'english', 'french', 'german')
Example:
const language = steam.getCurrentGameLanguage();
console.log('Steam language:', language);
// Load appropriate translations
switch (language) {
case 'french':
loadFrenchTranslations();
break;
case 'german':
loadGermanTranslations();
break;
case 'japanese':
loadJapaneseTranslations();
break;
case 'schinese':
loadSimplifiedChineseTranslations();
break;
case 'tchinese':
loadTraditionalChineseTranslations();
break;
default:
loadEnglishTranslations();
}Common Language Codes:
| Code | Language |
|---|---|
english |
English |
french |
French |
german |
German |
spanish |
Spanish (Spain) |
latam |
Spanish (Latin America) |
italian |
Italian |
japanese |
Japanese |
korean |
Korean |
portuguese |
Portuguese |
brazilian |
Portuguese (Brazil) |
russian |
Russian |
schinese |
Simplified Chinese |
tchinese |
Traditional Chinese |
thai |
Thai |
polish |
Polish |
danish |
Danish |
dutch |
Dutch |
finnish |
Finnish |
norwegian |
Norwegian |
swedish |
Swedish |
hungarian |
Hungarian |
czech |
Czech |
romanian |
Romanian |
turkish |
Turkish |
arabic |
Arabic |
bulgarian |
Bulgarian |
greek |
Greek |
ukrainian |
Ukrainian |
vietnamese |
Vietnamese |
Localization Example:
import SteamworksSDK from 'steamworks-ffi-node';
import * as fs from 'fs';
import * as path from 'path';
const steam = SteamworksSDK.getInstance();
steam.init({ appId: 480 });
// Get Steam language
const language = steam.getCurrentGameLanguage();
console.log(`Steam is running in: ${language}`);
// Load localized strings
const localizationPath = path.join(
__dirname,
'localization',
`${language}.json`
);
let strings;
if (fs.existsSync(localizationPath)) {
strings = JSON.parse(fs.readFileSync(localizationPath, 'utf8'));
console.log(`✅ Loaded ${language} translations`);
} else {
// Fallback to English
strings = JSON.parse(
fs.readFileSync(
path.join(__dirname, 'localization', 'english.json'),
'utf8'
)
);
console.log(`⚠️ No translations for ${language}, using English`);
}
// Use localized strings
console.log(strings.welcomeMessage);
console.log(strings.playButton);Returns: Returns 'english' as fallback if:
- Steam API is not initialized
- Apps interface is unavailable
- An error occurs retrieving the language
Best Practice: Get language early in initialization to set up localization:
const steam = SteamworksSDK.getInstance();
if (steam.init({ appId: 480 })) {
// Get language immediately after init
const language = steam.getCurrentGameLanguage();
// Initialize your localization system
i18n.locale = language;
// Continue with game initialization
await loadGameAssets(language);
}These methods are used internally by other modules:
Check if Steam API is initialized.
if (this.apiCore.isInitialized()) {
// Safe to make Steam API calls
}Get the ISteamUserStats interface handle.
const userStatsInterface = this.apiCore.getUserStatsInterface();
if (userStatsInterface) {
// Can call ISteamUserStats functions
}Get the ISteamUser interface handle.
const userInterface = this.apiCore.getUserInterface();
if (userInterface) {
// Can call ISteamUser functions
}The Steam API requires a steam_appid.txt file in your application directory. The init() method creates this automatically in the current working directory, and also sets the SteamAppId environment variable.
Automatic Creation:
// When you call init(), it automatically:
// 1. Sets process.env.SteamAppId = "480"
// 2. Creates steam_appid.txt in process.cwd()
steam.init({ appId: 480 });Manual Creation (optional):
echo "480" > steam_appid.txtLocation: Current working directory (process.cwd())
Causes:
- Steam client not running
- User not logged into Steam
- Invalid App ID
- Missing Steamworks SDK redistributables
Solution:
if (!steam.isSteamRunning()) {
console.error('Steam client is not running');
return;
}
const success = steam.init({ appId: 480 });
if (!success) {
console.error('Initialization failed');
console.log('Check:');
console.log('1. Steam is running');
console.log('2. You are logged in');
console.log('3. App ID is valid');
}Cause: API not initialized
Solution:
const status = steam.getStatus();
if (!status.initialized) {
console.error('Initialize Steam first');
steam.init({ appId: 480 });
}import SteamworksSDK from 'steamworks-ffi-node';
async function steamExample() {
const steam = SteamworksSDK.getInstance();
// Check if Steam is running
if (!steam.isSteamRunning()) {
console.error('❌ Steam client not running');
return;
}
// Initialize
console.log('🔌 Connecting to Steam...');
const initialized = steam.init({ appId: 480 });
if (!initialized) {
console.error('❌ Failed to initialize Steam API');
return;
}
console.log('✅ Connected to Steam!');
// Get status
const status = steam.getStatus();
console.log(`📊 Steam ID: ${status.steamId}`);
console.log(`📊 App ID: ${status.appId}`);
// Do work with managers...
const achievements = await steam.achievements.getAllAchievements();
console.log(`Found ${achievements.length} achievements`);
// Process callbacks
steam.runCallbacks();
// Cleanup
console.log('🧹 Shutting down...');
steam.shutdown();
console.log('✅ Disconnected');
}
// Handle cleanup on exit
process.on('SIGINT', () => {
const steam = SteamworksSDK.getInstance();
steam.shutdown();
process.exit(0);
});
steamExample();// ✅ Good - Create instance when needed
const steam = SteamworksSDK.getInstance();
steam.init({ appId: 480 });
// Multiple instances are fine
const steam1 = SteamworksSDK.getInstance();
const steam2 = SteamworksSDK.getInstance();// ✅ Good
const steam = SteamworksSDK.getInstance();
try {
steam.init({ appId: 480 });
// ... work ...
} finally {
steam.shutdown();
}// ✅ Good - Check before operations
const steam = SteamworksSDK.getInstance();
if (!steam.getStatus().initialized) {
steam.init({ appId: 480 });
}
await steam.achievements.getAllAchievements();// ✅ Good - Regular callback processing
setInterval(() => {
steam.runCallbacks();
}, 1000);
// Or after operations
await steam.achievements.unlockAchievement('ACH_WIN_ONE_GAME');
steam.runCallbacks();// ✅ Good - Handle initialization failure
const initialized = steam.init({ appId: 480 });
if (!initialized) {
console.error('Failed to connect to Steam');
// Show user-friendly error
// Provide fallback behavior
return;
}- Requires Steam client installed and running
- Works with both 32-bit and 64-bit applications
- Steam typically installed in
C:\Program Files (x86)\Steam
- Requires Steam.app running
- Steam typically in
/Applications/Steam.app - Library loaded from bundle:
Steam.AppBundle/Steam/Contents/MacOS
- Requires Steam client running
- Works with both 32-bit and 64-bit
- Steam typically installed in
~/.steamor~/.local/share/Steam
-
Check Steam is running:
console.log('Steam running:', steam.isSteamRunning());
-
Verify App ID:
- Use 480 (Spacewar) for testing
- Make sure your game's App ID is correct
- App must be in your Steam library
-
Check logs:
- Look for
[Steamworks]prefixed messages in console - Check for error messages from Steam
- Look for
-
Verify redistributables:
- Ensure
steamworks_sdk/redistributable_bin/exists in package - Check platform-specific library is present:
- Windows:
steam_api64.dllorsteam_api.dll - macOS:
libsteam_api.dylib - Linux:
libsteam_api.so
- Windows:
- Ensure