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:
The presence features used in a unified friends list require at minimum the openid sdk.social_layer_presence scopes. Use Client::GetDefaultPresenceScopes in your authorization flow.

Key concepts

The Discord friends list is constructed from two entities: Relationships and Users.

Relationships

Relationships are how Discord models friends, friend requests, blocks, and more. All relationships for the current user are loaded when the client connects. Each relationship has a target user ID and a type:
Relationship typeDescription
FriendConfirmed friendship
PendingOutgoingSent friend request, waiting for acceptance
PendingIncomingReceived friend request, waiting for your response
BlockedBlocked user
Each relationship also has both a DiscordRelationshipType (from Discord) and a GameRelationshipType (from your game).

Users

The UserHandle object contains information about a Discord user — their username, display name, avatar, online status, and current activity.
UserHandle objects maintain references to both the underlying data and the SDK instance. When their data changes, existing handle objects automatically reflect the changes without needing to be recreated.

User status and rich presence

The SDK provides two types of status:
  • Online status — Online, Offline, Idle, DoNotDisturb
  • Rich presence (game activity) — Activities associated with the current game only. You cannot see activities from other games, even if visible in the Discord client.

This approach is recommended. It significantly reduces code and ensures your friends list follows Discord’s recommended grouping and sort order.
The SDK automatically organizes friends into three groups defined by RelationshipGroupType:
GroupDescription
OnlinePlayingGameFriends who are online and currently playing your game
OnlineElsewhereFriends who are online but not playing your game
OfflineFriends who are offline
Within each group, the SDK automatically sorts users (for example, users who have played your game recently are moved to the top of OnlineElsewhere).

Step 1: Display the unified friends list

Use Client::GetRelationshipsByGroup to retrieve the pre-sorted list for each group:
void DisplayUnifiedFriendsList(const std::shared_ptr<discordpp::Client>& client) {
    const auto onlineInGame = client->GetRelationshipsByGroup(
        discordpp::RelationshipGroupType::OnlinePlayingGame
    );
    const auto onlineElsewhere = client->GetRelationshipsByGroup(
        discordpp::RelationshipGroupType::OnlineElsewhere
    );
    const auto offline = client->GetRelationshipsByGroup(
        discordpp::RelationshipGroupType::Offline
    );

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

            if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) {
                displayStr += " [Discord]";
            }
            if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) {
                displayStr += " [Game]";
            }

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

    std::cout << "\n=== Online - Elsewhere (" << onlineElsewhere.size() << ") ===\n";
    for (const auto& relationship : onlineElsewhere) {
        auto user = relationship.User();
        if (user) {
            std::cout << user->DisplayName() << "\n";
        }
    }

    std::cout << "\n=== Offline (" << offline.size() << ") ===\n";
    for (const auto& relationship : offline) {
        auto user = relationship.User();
        if (user) {
            std::cout << user->DisplayName() << "\n";
        }
    }
}

Step 2: Set up automatic updates

Use Client::SetRelationshipGroupsUpdatedCallback to keep your friends list current. This callback fires whenever a friend goes online or offline, starts playing your game, or when a relationship changes (friend request accepted, user blocked, etc.).
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

This approach gives you more control over filtering and display logic.

Step 1: Fetch relationships

Use Client::GetRelationships to retrieve all relationships:
void DisplayFriendsList(std::shared_ptr<discordpp::Client> client) {
    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 to confirmed friends only
        // Display pending requests and blocks in a separate management view
        if (relationship.DiscordRelationshipType() != discordpp::RelationshipType::Friend) {
            continue;
        }

        std::string str = user->DisplayName();

        // Indicate Discord friend (use the Discord logo in your actual UI)
        if (relationship.DiscordRelationshipType() == discordpp::RelationshipType::Friend) {
            str += " [Discord]";
        }

        // Indicate game friend
        if (relationship.GameRelationshipType() == discordpp::RelationshipType::Friend) {
            str += " [Game]";
        }

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

        // Categorize based on status
        if (user->GameActivity()) {
            inGame.push_back(str);
        } else if (user->Status() != discordpp::StatusType::Offline) {
            online.push_back(str);
        } else {
            offline.push_back(str);
        }
    }

    // Sort each category alphabetically
    std::sort(inGame.begin(), inGame.end());
    std::sort(online.begin(), online.end());
    std::sort(offline.begin(), offline.end());

    std::cout << "\n=== Online - GameTitle (" << inGame.size() << ") ===\n";
    for (const auto& str : inGame) {
        std::cout << str << "\n";
    }

    std::cout << "\n=== Online - Elsewhere (" << online.size() << ") ===\n";
    for (const auto& str : online) {
        std::cout << str << "\n";
    }

    std::cout << "\n=== Offline (" << offline.size() << ") ===\n";
    for (const auto& str : offline) {
        std::cout << str << "\n";
    }
}
This example rebuilds the list from scratch on each call. In a production game, maintain a cached collection of UserHandle objects and update it incrementally.
Call DisplayFriendsList when the client is ready:
client->SetStatusChangedCallback([client](discordpp::Client::Status status,
    discordpp::Client::Error error, int32_t errorDetail) {
    if (status == discordpp::Client::Status::Ready) {
        DisplayFriendsList(client);
    }
});

Step 2: Monitor user status changes

Use Client::SetUserUpdatedCallback to refresh the list when a user’s presence or info changes:
client->SetUserUpdatedCallback([&client](uint64_t userId) {
    std::cout << "User updated: " << userId << std::endl;
    DisplayFriendsList(*client);
});

Step 3: Monitor relationship changes

Set up callbacks for when relationships are created or deleted:
// Fires when a friend request is sent/accepted, or a user is blocked
client->SetRelationshipCreatedCallback([&client](uint64_t userId,
    bool isDiscordRelationshipUpdate) {
    std::optional<discordpp::UserHandle> user = client->GetUser(userId);
    if (user) {
        std::cout << "Relationship created: " << user->DisplayName() << std::endl;
        DisplayFriendsList(*client);
    }
});

// Fires when a friend request is rejected or a friend is removed
client->SetRelationshipDeletedCallback([&client](uint64_t userId,
    bool isDiscordRelationshipUpdate) {
    std::cout << "Relationship deleted: " << userId << std::endl;
    DisplayFriendsList(*client);
});

Next steps

Managing relationships

Allow players to manage friends, friend requests, and blocked users.

Setting rich presence

Display game status and activity information to Discord friends.

Managing lobbies

Bring players together in a shared lobby with text chat and voice communication.

Change log

DateChanges
July 17, 2025Add SDK helper methods for unified friends list
March 17, 2025Initial release