Skip to main content

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:

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 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 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).
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 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

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. 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:
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.
// 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:
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());
    }
}
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:
// 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, 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.
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.
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).
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.
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.
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.
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.
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: Need help? Join the Discord Developers Server and share questions in the #social-sdk-dev-help channel for support from the community. If you encounter a bug while working with the Social SDK, please report it here: https://dis.gd/social-sdk-bug-report

Change Log

DateChanges
March 17, 2025Initial release
July 17, 2025Add UFL helper methods