> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing title-managed stats

> XSAPI example code that calls XblTitleManagedStatsUpdateStatsAsync to selectively update a player's title-managed XBOX Live stat values.

This topic provides example code showing how to write title-managed stats.

<Note>The stored stat value reflects the value most recently written through these APIs. However, the **global leaderboard for that stat retains only the highest recorded value** per player, so writing a lower value doesn't lower the player's leaderboard position. For details and alternatives, see the [title-managed Stats overview](/services/xbox-services/player-data/stats-leaderboards/title-managed/live-stats-tm-overview) and the [`XblLeaderboardQuery`](/reference/live/xsapi-c/leaderboard_c/structs/xblleaderboardquery) reference.</Note>

## Updating only the specified title-managed stats

You can send specified stats that you want to update, by calling [XblTitleManagedStatsUpdateStatsAsync](/reference/live/xsapi-c/title_managed_statistics_c/functions/xbltitlemanagedstatsupdatestatsasync), which selectively updates the calling user's stats.
A specified stat will only be overwritten if it already exists. Any stats that aren't specified in the call to `XblTitleManagedStatsUpdateStatsAsync` stay unchanged.

**C API**

```cpp theme={null}
std::vector<XblTitleManagedStatistic> stats{ s_svd->Stats() };
auto stat1 = std::find_if(stats.begin(), stats.end(), [](const XblTitleManagedStatistic& s)
{
    return std::string{ "AddedStat" } == s.statisticName;
});

auto asyncBlock = std::make_unique<XAsyncBlock>();
asyncBlock->queue = Data()->queue;
asyncBlock->callback = [](XAsyncBlock* asyncBlock)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*
    HRESULT hr = XAsyncGetStatus(asyncBlock, false);
};

HRESULT hr = XblTitleManagedStatsUpdateStatsAsync(
    Data()->xboxLiveContext,
    &(*stat1),
    1,
    asyncBlock.get()
);

if (SUCCEEDED(hr))
{
    // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.
    // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*
    asyncBlock.release();
}
```

**Reference**

* [XAsyncBlock](/reference/system/xasync/structs/xasyncblock)
* [XAsyncGetStatus](/reference/system/xasync/functions/xasyncgetstatus)
* [XblTitleManagedStatistic](/reference/live/xsapi-c/title_managed_statistics_c/structs/xbltitlemanagedstatistic)
* [XblTitleManagedStatsUpdateStatsAsync](/reference/live/xsapi-c/title_managed_statistics_c/functions/xbltitlemanagedstatsupdatestatsasync)

## Writing all the stats you want to keep, and deleting the rest

To write only the title-managed stats that you want to keep, and delete the rest, call [XblTitleManagedStatsWriteAsync](/reference/live/xsapi-c/title_managed_statistics_c/functions/xbltitlemanagedstatswriteasync) with all the stats you want to write.
Any stats that are not included in the call will be removed. This call replaces the last stats document on the service with a new stats document that contains only the values you sent.

**C API**

```cpp theme={null}
std::vector<XblTitleManagedStatistic> statList;
statList.push_back(XblTitleManagedStatistic{ "MyStatName1", XblTitleManagedStatType::Number, 200 });
statList.push_back(XblTitleManagedStatistic{ "MyStatName2", XblTitleManagedStatType::String, 0, "SomeValue" });

auto asyncBlock = std::make_unique<XAsyncBlock>();
asyncBlock->queue = queue;
asyncBlock->context = nullptr;
asyncBlock->callback = [](XAsyncBlock* asyncBlock)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*
    HRESULT hr = XAsyncGetStatus(asyncBlock, false);
};

HRESULT hr = XblTitleManagedStatsWriteAsync(
    xboxLiveContext, 
    xboxUserId, 
    statList.data(), statList.size(), 
    asyncBlock.get());
if (SUCCEEDED(hr))
{
    // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.
    // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*
    asyncBlock.release();
}
```

**Reference**

* [XAsyncGetStatus](/reference/system/xasync/functions/xasyncgetstatus)
* [XblTitleManagedStatistic](/reference/live/xsapi-c/title_managed_statistics_c/structs/xbltitlemanagedstatistic)
* [XblTitleManagedStatsWriteAsync](/reference/live/xsapi-c/title_managed_statistics_c/functions/xbltitlemanagedstatswriteasync)
* [XblTitleManagedStatType](/reference/live/xsapi-c/title_managed_statistics_c/enums/xbltitlemanagedstattype)


## Related topics

- [Title-managed Stats and Leaderboards example code](/services/xbox-services/player-data/stats-leaderboards/title-managed/how-to/live-statslb-tm-howto-nav.md)
- [Configure title-managed Stats and Leaderboards](/services/xbox-services/player-data/stats-leaderboards/title-managed/config/live-tm-leaderboards-portal.md)
- [How to](/services/xbox-services/player-data/stats-leaderboards/title-managed/how-to/index.md)
- [Event-based Stats VS. title-managed Stats](/services/xbox-services/player-data/stats-leaderboards/live-stats-eb-vs-tm.md)
- [Title-managed Stats & Leaderboards](/services/xbox-services/player-data/stats-leaderboards/title-managed/live-statslb-tm-nav.md)
