If Steam overlay works but achievements never unlock in your Unity build, the issue is usually not the achievement definition itself.
Most failures come from one of four places: wrong App ID context, SteamAPI not initialized early enough, callbacks not pumped, or SetAchievement never committed with StoreStats.
This guide gives you a deterministic fix order you can run before release.
Problem summary
Typical symptoms:
- Achievement conditions are met in gameplay, but no unlock toast appears.
- No obvious exception is thrown, so teams assume Steam sync is delayed.
- Unlocks may work in Editor tests but fail in standalone development or release builds.
- Logs show wrapper calls succeeded, but backend state never changes.
Impact:
- Player trust drops quickly when progression rewards fail.
- QA cannot verify milestone goals tied to achievements.
- Launch-week support load spikes around "achievement broken" reports.
Why this happens
Achievements in Steamworks require a complete flow:
- Steam API initialized for the correct App ID
- User stats requested and loaded
- Achievement set by API call
- Stats committed with
StoreStats - Callbacks pumped so async responses are processed
If any one step is missing or happens out of order, unlocks silently fail.
Official references:
Step 1 - Confirm App ID and build context
- Verify your configured App ID matches the achievement set on Steamworks partner site.
- For local development builds, confirm
steam_appid.txtcontains only the correct numeric App ID. - Ensure the Steam account used for testing has permission to access this app context.
If you test with the wrong App ID, unlock calls can appear successful locally but never land in the target backend.
Step 2 - Initialize SteamAPI before achievement code runs
Initialize Steam once at startup, before gameplay systems try to unlock achievements.
Use one bootstrap path, not multiple partial init calls across scenes.
// Example order
SteamAPI.Init();
SteamUserStats.RequestCurrentStats();
// Later in gameplay:
SteamUserStats.SetAchievement("ACH_WIN_FIRST_MATCH");
SteamUserStats.StoreStats();
If your achievement manager runs before stats are ready, store requests can fail silently.
Step 3 - Pump callbacks every frame
Steam callbacks are asynchronous.
You must call callback pump logic in your update loop.
Without callback pumping, requests and commits can remain pending:
- stats request callback never resolves
- achievement unlock callback never confirms
- QA sees inconsistent behavior between long and short sessions
Keep callback pumping in a persistent object that survives scene loads.
Step 4 - Validate unlock and commit sequence
When criteria are met:
- Call
SetAchievement(achievementId) - Immediately call
StoreStats() - Log both return values and callback result codes
Do not assume SetAchievement alone is enough for persistence.
Minimal verification log fields
timestamp | appId | achievementId | setResult | storeResult | callbackResult
This gives you fast evidence when triaging release-week failures.
Step 5 - Check script lifecycle and duplicate managers
Common Unity-side regressions:
- duplicate Steam managers after scene transitions
- manager destroyed and recreated without full init
- achievement calls from disabled objects after teardown
Use one persistent manager (DontDestroyOnLoad) and guard against duplicate instances.
Verification checklist
- [ ] Steam overlay appears in the same build where you test achievements
- [ ]
RequestCurrentStatscompletes before unlock attempts - [ ]
SetAchievementandStoreStatsboth return expected success state - [ ] Callback pump runs each frame while the game is active
- [ ] Achievement unlock is visible in Steam client profile for test account
Alternative fixes
- If unlocks work only after restart, add stronger logging around stats-ready state and defer unlock until stats callback confirms.
- If only some achievements fail, verify exact API IDs against partner-site definitions (case and spelling).
- If unlocks fail only on one machine, verify Steam client login context and app entitlement on that account.
Prevention tips
- Keep achievement IDs as constants in one file, not scattered string literals.
- Add one automated smoke script that unlocks a test achievement in a controlled build.
- Freeze Steamworks wrapper updates close to release unless a blocker requires upgrade.
- Record your known-good initialization order in project docs.
FAQ
Why do achievements unlock in Editor tests but fail in standalone builds?
Editor flow can hide ordering and lifecycle issues. Standalone builds expose real initialization timing, callback handling, and persistence behavior.
Do we need to call StoreStats every time?
For reliable persistence, yes after setting achievement or stat changes. Batch carefully, but do not skip commits.
Related links
- Steamworks Init Failed in Unity Editor - Native Plugin Path and Platform Fix
- Steamworks Callbacks Not Firing in Unity Editor - Run in Background and Pump Timing Fix
- Steamworks DLC Not Detected in Unity Build - App Ownership Query and Depot Config Fix
- Unity guide
Bookmark this fix before your next build-candidate cycle so achievement regressions are caught before players report them.