Skip to main content
In the XBOX Game Development Kit (GDK) and in Steam, achievements have information like the name, description, icon, and whether it has been unlocked for the current user, and optionally, the progress toward completing them. Steam also has a stats API that’s used by games to compare a user’s progress to some predetermined target and unlock achievements when these targets are surpassed. In fact, the XBOX Game Development Kit (GDK) actually has two achievement APIs: event-based (previously called Achievements 2013) and title-managed (previously called Achievements 2017). While both systems are viable options, title-managed achievements/stats will be much more familiar to you if you’re coming from Steam and will match the existing logic that’s likely present in your game. For this reason, we’ll describe that API in this topic. For more information about the differences between the two APIs, see Event-based vs. title-managed Achievements. The following sections describe the differences between achievements in the Steamworks API and the XBOX Game Development Kit (GDK). To use the title-managed achievements APIs, you need to create an XBOX services Context handle. This can be done by using the XblContextCreateHandle function and an XUserHandle from XUserAddResult API (from the User authentication and ownership topic).

Keeping track of achievement progress

In the Steam API, you can use the ISteamUserStats::GetStat/ISteamUser::SetStat API to keep track of a user’s progress toward an achievement, making the values stored in the Steam Stats API the source of truth for what the current progress value is. With title-managed achievements, your game is the single source of truth and must keep track of the user’s current progress on its own. Updating the current progress in the cloud with an API call is done as a sort of “check in” and is used to show a user’s progress in some surfaces across the XBOX ecosystem. There isn’t specific guidance on where the current progress value should live, but many games choose to store it in their save file (and in the cloud), while others might store it on their own backend service. Be sure to keep the values between the cloud and your game’s internal stat management system in sync with each other.

Enumerating all achievements

To get all a user’s stats with the Steamworks API, you would usually call ISteamUserStats::RequestUserStats to pull the latest stats from the server. After it has fired its corresponding callback, you could then iterate through each achievement by its API name by using the ISteamUserStats::GetStat/ISteamUserStats::GetAchievement functions and initializing the game state by using the data they returned. With the XBOX Game Development Kit (GDK), you can simply use the XblAchievementsGetAchievementsForTitleIdAsync function and then use the data in each achievement object in the array provided as the Out parameter of XblAchievementsResultGetAchievements to initialize your game state. Each achievement is provided as an XblAchievement struct. For more information about the data it contains, see its reference topic.

Steamworks

XBOX Game Development Kit (GDK)

For more information about title-managed achievements, see Getting title-managed Achievements.

Updating an achievement’s progress and unlocking achievements

In the XBOX Game Development Kit (GDK) and in Steam, the game’s code determines when an achievement should be unlocked. With the XBOX Game Development Kit (GDK), setting an achievement to a progress of 100 unlocks it. The following sections describe the steps that are required to update a user’s progress on a specified achievement with both APIs. Following is a code example for an UpdateAchievement method, implemented in both SDKs, that takes in an achievement ID/API name (and stat API name in Steam), how much to increment the achievement by, what the target value is to unlock that achievement, and updates the progress and unlocks the status of the achievement accordingly.

Steamworks

XBOX Game Development Kit (GDK)

For more information about title-managed achievements, see Updating title-managed Achievements.

Offline achievements

Unlocking an XBOX achievement doesn’t require a network connection. It automatically unlocks with the server later without additional code if the user isn’t connected to XBOX network (also known as XBOX Live).

Getting another user’s achievements

To get another user’s achievements, you can simply call the XblAchievementsGetAchievementsForTitleAsync/XblAchievementsGetAchievementAsync functions with the XBOX User ID (XUID) of the user whose achievements you want to fetch. This is similar to using the ISteamUser::RequestUserStats, ISteamUserStats::GetUserStat, and ISteamUserStats::GetUserAchievement functions in Steam.

Resetting achievements

Unlike the Steamworks API’s ISteamUserStats::ResetAllStats, which can be used to reset the user’s progress on all their stats and—if specified—achievements, the XBOX Game Development Kit (GDK) has no documented ability to programmatically reset achievement progress or unlock status. Attempting to call XblAchievementsUpdateAchievementAsync with a progress value of 0 leaves the progress value unchanged. However, you can use the Player Data Reset tool (XblPlayerDataReset.exe) when testing to accomplish this.

Rate limiting

When updating achievement progress, be careful to avoid hitting the XBOX Services API (XSAPI) too often, because it may cause your game to hit its rate limit. This can cause unexpected behavior and a bad experience for your users. For achievements that track stats that are frequently updated, try batching API calls to be fired after a certain number of events happen or to update on the server at a certain time interval. You can debug your API calls by using the XBOX services Trace Analyzer (XblTraceAnalyzer.exe). For more information about rate limiting on XBOX services, see Fine-Grained Rate Limiting.
Last modified on August 20, 2026