---
sidebar_label: Creating a Unified Friends List
---
import PublicClient from '../partials/callouts/public-client.mdx';
import SupportCallout from '../partials/callouts/support.mdx';

[Home](/docs/intro) > [Discord Social SDK](/docs/discord-social-sdk/overview) > [Development Guides](/docs/discord-social-sdk/development-guides) > {sidebar_label}

# Creating a Unified Friends List

## Overview

A unified friends list combines both Discord and game-specific relationships in one view. This guide will show you how to:
- Fetch all relationship data
- Filter and organize relationships
- Display online status
- Handle different relationship types

### Prerequisites

Before you begin, make sure you have:
- Set up the Discord Social SDK with [Getting Started Guide](/docs/discord-social-sdk/getting-started)
- Authenticated your users with [Development Guide: Account Linking](/docs/discord-social-sdk/development-guides/account-linking-with-discord)
- Understanding of relationship types with [Development Guide: Managing Relationships in Your Game](/docs/discord-social-sdk/development-guides/managing-relationships)

### Implementing a Unified Friends List

The Discord friend list is ultimately constructed from two entities: Relationships, and Users. You can query
Relationships API to find everyone a user is a friend with, and the Users API to find the necessary extra information
for rendering the list, such as whether they are online or not.

### Relationships

[Relationships](/docs/discord-social-sdk/development-guides/managing-relationships) are how Discord models friends,
friend requests, and more. All relationships for the current user are loaded when the Client connects. Each
relationship has a target user id, and a type, such as `Friend`, `PendingOutgoing`, or `Blocked`.

To allow users to manage their relationships in your game, you should provide a way to accept or reject friend
requests, block users, and manage pending requests. See [Development Guide: Managing Relationships in Your Game](/docs/discord-social-sdk/development-guides/managing-relationships) for implementation details.

### Users

Users are the Discord users that are part of the relationships. The SDK provides a way to fetch a user by their ID, and the user object contains information such as their username, display name, avatar, and more.

### User Status & Rich Presence

Presence is how Discord stores whether a user is currently online or not, as well as what activities they are currently doing (such as playing a game). The SDK gives you access to two types of status:

- Online Status: Online, Offline, Idle, etc.
- Rich Presence: Any activities associated with the current game (or application in Discord parlance).  

:::info
The SDK will only display activities associated with the current game, meaning you will not be able to see other game activities in Rich Presence, even if you can see them in the Discord client.
:::

See our [Design Guidelines: Status & Rich Presence](/docs/discord-social-sdk/design-guidelines/status-rich-presence) for best practices on displaying presence information.

There are two ways in which you can create a unified friends list in your game:

1. Using the SDK Unified Friends List helper functions, which automatically group and sort
relationships and users for you.
2. Directly retrieving relationships and users from the SDK, and sorting manually.

## Approach 1: Using SDK Unified Friends List Helper Functions

:::info
This approach is recommended as it significantly reduces the amount of code you need to write and maintain compared to
manually fetching and organizing relationships, while ensuring your friends list follows Discord's best practices.
:::

The Discord Social SDK provides built-in helper functions that automatically group and sort your friends list according
to Discord's [recommended design guidelines](/docs/discord-social-sdk/design-guidelines/unified-friends-list).
This approach is generally simpler and more maintainable than manually fetching and organizing relationships.

The SDK automatically organizes friends into the three groups we find via [`RelationshipGroupType`]:
- `OnlinePlayingGame`: Friends who are online and currently playing your game
- `OnlineElsewhere`: Friends who are online but not playing your game
- `Offline`: Friends who are offline

### Step 1: Display the Unified Friends List

The [`Client::GetRelationshipsByGroup`] method returns a pre-sorted list of relationships for a specific group type.
This eliminates the need to manually filter, categorize, and sort friends yourself. The SDK handles all the logic
for determining which group each friend belongs to based on their online status and game activity, and
automatically sorts users within each group (for example, users who have played your game are moved to the top of
the OnlineElsewhere group).

Let's create a function that uses the SDK helper functions to display a properly organized friends list:

```cpp
void DisplayUnifiedFriendsList(const std::shared_ptr<discordpp::Client> &client) {
    // Get friends playing the game
  const auto onlineInGame = client->GetRelationshipsByGroup(
        discordpp::RelationshipGroupType::OnlinePlayingGame
    );

    // Get friends online elsewhere
    const auto onlineElsewhere = client->GetRelationshipsByGroup(
        discordpp::RelationshipGroupType::OnlineElsewhere
    );

    // Get offline friends
    const auto offline = client->GetRelationshipsByGroup(
        discordpp::RelationshipGroupType::Offline
    );

    // Display "Online - GameTitle" Friends
    std::cout << "\n=== Online - GameTitle (" << onlineInGame.size() << ") ===\n";
    for (const auto& relationship : onlineInGame) {
        auto user = relationship.User();
        if (user) {
            std::string displayStr = "🟣 " + user->DisplayName();

            // Add Discord friend indicator
            if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) {
                displayStr += " 👾";
            }

            // Add game friend indicator
            if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) {
                displayStr += " 🎮";
            }

            std::cout << displayStr << "\n";
        }
    }

    // Display "Online - Elsewhere" Friends
    std::cout << "\n=== Online - Elsewhere (" << onlineElsewhere.size() << ") ===\n";
    for (const auto& relationship : onlineElsewhere) {
        auto user = relationship.User();
        if (user) {
            std::string displayStr = "🟢 " + user->DisplayName();

            // Add Discord friend indicator
            if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) {
                displayStr += " 👾";
            }

            // Add game friend indicator
            if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) {
                displayStr += " 🎮";
            }

            std::cout << displayStr << "\n";
        }
    }

    // Display "Offline" Friends
    std::cout << "\n=== Offline (" << offline.size() << ") ===\n";
    for (const auto& relationship : offline) {
        auto user = relationship.User();
        if (user) {
            std::string displayStr = "⚫ " + user->DisplayName();

            // Add Discord friend indicator
            if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) {
                displayStr += " 👾";
            }

            // Add game friend indicator
            if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) {
                displayStr += " 🎮";
            }

            std::cout << displayStr << "\n";
        }
    }
}
```

### Step 2: Set Up Automatic Updates

To keep your friends list up-to-date automatically, use the [`Client::SetRelationshipGroupsUpdatedCallback`]. This
callback is triggered whenever any change occurs that might affect the friends list grouping, such as a friend going
online or offline, or when a relationship changes, such as when you accept a friend request, or block a user.

```cpp
// Set up the unified friends list update callback
client->SetRelationshipGroupsUpdatedCallback([&client](const uint64_t userId) {
    std::cout << "👥 Friends list updated for user: " << userId << std::endl;
    DisplayUnifiedFriendsList(client);
});
```

---

## Approach 2: Manually Fetching Relationships and Users

In this section we'll show a more manual method which gives you more control over how the friends list is displayed in your game.

### Step 1: Fetch Relationships

First, let's create a function that utilises [`Client::GetRelationships`] to query all the relationships and
user information we for our account:

```cpp
void DisplayFriendsList(discordpp::Client& client) {
    std::vector<std::string> relationships{};
    for (auto& relationship: client->GetRelationships()) {
        auto user = relationship.User();
        if (!user) {
            continue;
        }
    
        std::string str{};
        // Identifying information about the user:
        str += " DiscordName: " + user->DisplayName();
        str += " DiscordId: " + std::to_string(user->Id());
        // Provisional users don't have a Discord icon shown next to them:
        str += " IsProvisional: " + std::to_string(user->IsProvisional());
        // Whether the relationship is for a friend, a friend request, or because the user is blocked:
        // For a friends list you'll want to filter out blocked users
        // And likely display friend requests in a different section
        str += " DiscordRelationshipType: " + std::string(discordpp::EnumToString(relationship.DiscordRelationshipType()));
        str += " GameRelationshipType: " + std::string(discordpp::EnumToString(relationship.GameRelationshipType()));
        // Whether the user is online/offline/etc:
        str += " IsOnlineAnywhere: " + std::to_string(user->Status() != discordpp::StatusType::Offline);
        str += " IsOnlineInGame: " + std::to_string(user->GameActivity() != std::nullopt);
        relationships.push_back(str);
    }
    
    std::sort(relationships.begin(), relationships.end());
    for (auto str : relationships) {
        printf("%s\n", str.c_str());
    }
}
```

:::info
The `relationship.User()` function returns a [`UserHandle`] object that represents a user that the Discord Social SDK
knows about.
Handle objects maintain references to both the underlying data and the SDK instance, which means that when their
data changes, existing handle objects automatically reflect these changes without needing to be recreated.
:::

We will want to call this function when the client is ready, so let's add it to our ready callback:

```cpp
// Set up status callback to monitor client connection
client->SetStatusChangedCallback([client](discordpp::Client::Status status, discordpp::Client::Error error, int32_t errorDetail) {
    std::cout << "🔄 Status changed: " << discordpp::Client::StatusToString(status) << std::endl;

    if (status == discordpp::Client::Status::Ready) {
        std::cout << "✅ Client is ready! You can now call SDK functions.\n";
        std::cout << "👥 Friends Count: " << client->GetRelationships().size() << std::endl;
        
        SetRichPresence(client);
        DisplayFriendsList(client);

    } else if (error != discordpp::Client::Error::None) {
        std::cerr << "❌ Connection Error: " << discordpp::Client::ErrorToString(error) << " - Details: " << errorDetail << std::endl;
    }
});
```

This will output the raw relationship data to the console. You can use this information to filter, organize and build a friends list that fits your game's design aesthetic.

---

### Step 2: Organize Relationships

Based on our design guidelines for a [Unified Friends List](/docs/discord-social-sdk/design-guidelines/unified-friends-list), you should separate the player's friends list into three sections: `Online - GameTitle`, `Online - Elsewhere`, and `Offline`. 

Because we are building a text console application, we will use emojis to represent the status of each friend but you can use your own design elements to convey status and presence in your game.

Let's update our `DisplayFriendsList` function to reflect our three sections and categorize friends based on their status:

- We will create three vectors to store the friends in each category.
- We will filter out pending friends and blocked users.
- We will add indicators for Discord friends, game friends, and provisional users.
- We will categorize friends based on their game and presence status.
- We will sort each category alphabetically.
- We will display each category separately.

:::info
This example is for reference only. Please make sure you use efficient data structures and cache data when appropriate to avoid performance issues in your game.
:::

```cpp
void DisplayFriendsList(std::shared_ptr<discordpp::Client> client) {
    // Create vectors for each section
    std::vector<std::string> inGame;
    std::vector<std::string> online;
    std::vector<std::string> offline;
    
    for (auto& relationship : client->GetRelationships()) {
        auto user = relationship.User();
        if (!user) {
            continue;
        }

        // Filter out pending friends and blocked users
        // You can display friend requests and blocked users in a different view to allow players to manage them in your game
        if (relationship.DiscordRelationshipType() != discordpp::RelationshipType::Friend) {
            continue;
        }
 
        std::string str;
        str += user->DisplayName();

        // Add Discord friend indicator
        // In a real game, please use the official Discord logo available in our design guidelines
        if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) {
            str += " 👾";
        }

        // Add game friend indicator
        if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) {
            str += " 🎮";
        }

        // Add provisional indicator
        if (user->IsProvisional()) {
            str += " (Provisional)";
        }

        // Categorize based on status
        if (user->GameActivity()) {
            // in game
            inGame.push_back("🟣 " + str);
        } else if (user->Status() != discordpp::StatusType::Offline) {
            // online
            online.push_back("🟢 " + str);
        } else {
            // offline
            offline.push_back("⚫ " + str);
        } 
    }
    
    // Sort each category
    std::sort(inGame.begin(), inGame.end());
    std::sort(online.begin(), online.end());
    std::sort(offline.begin(), offline.end());
    
    // Display "Online - GameTitle" Friends
    std::cout << "\n=== Online - GameTitle (" << inGame.size() << ") ===\n";
    for (const auto& str : inGame) {
        std::cout << str << "\n";
    }
    
    // Display "Online - Elsewhere" Friends
    std::cout << "\n=== Online - Elsewhere (" << online.size() << ") ===\n";
    for (const auto& str : online) {
        std::cout << str << "\n";
    }
    
    // Display "Offline" Friends
    std::cout << "\n=== Offline (" << offline.size() << ") ===\n";
    for (const auto& str : offline) {
        std::cout << str << "\n";
    }
}
```

If we build and run our application, we should now see a list of friends separated into three categories: `Online - GameTitle`, `Online - Elsewhere`, and `Offline`.

### Step 3: Monitor Changes to Users

To monitor for user changes, we're going using the [`Client::SetUserUpdatedCallback`] function.

This callback will be triggered whenever a user's info is updated, such as name or presence changes (when they go online, offline, or start playing your game).

```cpp
client->SetUserUpdatedCallback([&client](uint64_t userId) {
    std::cout << "👤 User updated: " << userId << std::endl;
    DisplayFriendsList(*client);
});
```

Now your friends list will automatically update when the presence of a friend changes, such as when they go online, offline or start playing your game.

:::info
The automatic updates of the [`UserHandle`] object to the latest the user information should be sufficient for
retrieving the most up-to-date user information.
[`Client::SetUserUpdatedCallback`] may be more useful to identify times when you wish to re-sort your
user list, or similar operations.
:::
---

### Step 4: Monitor Changes in Relationships

Let us setup two callbacks to handle relationship updates.

:::warn
These examples rebuild the friends list from scratch every time a relationship changes. For performance reasons, we
recommend maintaining a collection of [`UserHandle`] objects and adding and removing them appropriately.
:::

#### Relationship Created Callback

This can happen when a user sends or accepts a friend invite, or blocks a user.

```cpp
client->SetRelationshipCreatedCallback([&client](uint64_t userId, bool isDiscordRelationshipUpdate) {
    std::optional<discordpp::UserHandle> user = client->GetUser(userId);
    // if the userid is valid (which it should be), we can display the user's display name
    if(user) {
        std::cout << "🤝 Relationship created: " << user->DisplayName() << std::endl;
        DisplayFriendsList(*client);
    }
});
```

#### Relationship Deleted Callback

This can happen when a user rejects a friend request or removes a friend.

```cpp
client->SetRelationshipDeletedCallback([&client](uint64_t userId, bool isDiscordRelationshipUpdate) {
    std::cout << "🔥 Relationship deleted: " << userId << std::endl;
    DisplayFriendsList(*client);
});
```

Now your friends list will automatically update when relationships change, such as when you add a new friend, accept a friend request, or block a user.

---

## Next Steps

Now that you have a unified friends list, you can build on your social features by allowing players to manage relationships, send game invites, and more. Check out our other guides for more information:

<Container>
  <Card title="Designing a Unified Friends List" link="/docs/discord-social-sdk/design-guidelines/unified-friends-list" icon="PaintPaletteIcon">
    Best practices for designing your Unified Friends List.
  </Card>
  <Card title="Managing Relationships" link="/docs/discord-social-sdk/development-guides/managing-relationships" icon="UserStatusIcon">
    Allow players to manage their friends, friend requests, and blocked users.
  </Card>
  <Card title="Managing Game Invites" link="/docs/discord-social-sdk/development-guides/managing-game-invites" icon="InboxIcon">
    Allow players to invite friends to join their game session or party.
  </Card>
</Container>

<SupportCallout />

---

## Change Log

| Date           | Changes                |
|----------------|------------------------|
| March 17, 2025 | Initial release        |
| July 17, 2025  | Add UFL helper methods |

{/* Autogenerated Reference Links */}
[`Client::GetRelationships`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ad481849835cd570f0e03adafcf90125d
[`Client::GetRelationshipsByGroup`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a9f7898d3f3d1ec92b06c662df70746d5
[`Client::SetRelationshipGroupsUpdatedCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#af12441ef091298f968075b7190851098
[`Client::SetUserUpdatedCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a3559f375165acedc6d6677ef599b3a4a
[`RelationshipGroupType`]: https://discord.com/developers/docs/social-sdk/namespacediscordpp.html#a503ed2f7b0bfbd435321a0e8b1dfba35
[`UserHandle`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1UserHandle.html#a587bcc838e42dc5c56f840a350070707