User Data API

hiimjasmine00

User Data API

An API for managing extra user data.

Features

  • Storing and retrieving extra user data from mods
  • Uploading user data to the API
  • Listening to events for user profiles, comments, friends, friend requests, and leaderboards

Usage

To use User Data API, include it as a dependency in your Geode mod by adding the following to your mod.json:

{
    "dependencies": {
        "hiimjasmine00.user_data_api": {
            "version": ">=v1.2.0",
            "required": true
        }
    }
}

"required" can be set to false if you want your mod to work without User Data API.

Then, include the headers in your code.

Required dependency:

#include 
#include 

Non-required dependency:

#include 
#define USER_DATA_API_EVENTS
#include 

API Methods

User Data API uses the user_data namespace. Its methods are included in ``.

  • user_data::contains(cocos2d::CCNode* node, std::string_view id): Checks if user data for the given mod ID (defaults to your mod ID) exists on the node.
  • user_data::downloading(cocos2d::CCNode* node): Checks if user data is currently being downloaded for the node.
  • user_data::get(cocos2d::CCNode* node, std::string_view id): Retrieves user data associated with the node and mod ID (defaults to your mod ID), and converts it to type T (defaults to matjson::Value).
  • user_data::upload(const matjson::Value& data, std::string_view id): Uploads user data to the API for the given mod ID (defaults to your mod ID).

The ID for User Data API can be retrieved using user_data::ID.

Events

The User Data API exposes events that let you react to web requests (such as loading profiles, comments, or leaderboards).

You can include them all with:

#include 

Or include only the specific event headers you need.

  • ``: Profile events
  • ``: Level/list comment events
  • ``: Profile comment events
  • ``: Friend & blocked user events
  • ``: Friend request events
  • ``: Leaderboard events
  • ``: Level leaderboard events
  • ``: User search events

Each event also supports an optional account ID filter to limit results.

The Events.hpp file also includes helper functions to make adding listeners easier, which are seen below. These functions automatically check if user data is being downloaded, and only call your function when the data is ready.

Profile Events

#include 
#include 

// Global listener
$on_mod(Loaded) {
    user_data::ProfileEvent().listen([](GJUserScore* score) {
        // Do something
    }).leak();
}

// Node-based listener
class $modify(ProfilePage) {
    void loadPageFromUserInfo(GJUserScore* score) {
        ProfilePage::loadPageFromUserInfo(score);

        user_data::handleProfilePage(this, [this](GJUserScore* score) {
            // Do something
        });
    }
};

Level/List Comment Events

#include 
#include 

// Global listener
$on_mod(Loaded) {
    user_data::CommentEvent().listen([](GJComment* comment) {
        // Do something
    }).leak();
}

// Node-based listener
class $modify(CommentCell) {
    void loadFromComment(GJComment* comment) {
        CommentCell::loadFromComment(comment);

        if (m_accountComment) return;

        user_data::handleCommentCell(this, [this](GJComment* comment) {
            // Do something
        });
    }
};

Profile Comment Events

#include 
#include 

// Global listener
$on_mod(Loaded) {
    user_data::ProfileCommentEvent().listen([](GJComment* comment) {
        // Do something
    }).leak();
}

// Node-based listener
class $modify(CommentCell) {
    void loadFromComment(GJComment* comment) {
        CommentCell::loadFromComment(comment);

        if (!m_accountComment) return;

        user_data::handleCommentCell(this, [this](GJComment* comment) {
            // Do something
        });
    }
};

Friend & Blocked User Events

#include 
#include 

// Global listener
$on_mod(Loaded) {
    user_data::FriendEvent().listen([](GJUserScore* score) {
        // Do something
    }).leak();
}

// Node-based listener
class $modify(GJUserCell) {
    void loadFromScore(GJUserScore* score) {
        GJUserCell::loadFromScore(score);

        auto friendReqStatus = score->m_friendReqStatus;
        if (friendReqStatus != 1 && friendReqStatus != 2) return;

        user_data::handleUserCell(this, [this](GJUserScore* score) {
            // Do something
        });
    }
};

Friend Request Events

#include 
#include 
#include 

// Global listener
$on_mod(Loaded) {
    user_data::FriendRequestEvent().listen([](GJUserScore* score) {
        // Do something
    }).leak();
}

// Node-based listener
class $modify(GJRequestCell) {
    void loadFromScore(GJUserScore* score) {
        GJRequestCell::loadFromScore(score);

        user_data::handleRequestCell(this, [this](GJUserScore* score) {
            // Do something
        });
    }
};
class $modify(GJUserCell) {
    void loadFromScore(GJUserScore* score) {
        GJUserCell::loadFromScore(score);

        if (score->m_friendReqStatus != 4) return;

        user_data::handleUserCell(this, [this](GJUserScore* score) {
            // Do something
        });
    }
};

Leaderboard Events

#include 
#include 

// Global listener
$on_mod(Loaded) {
    user_data::GlobalScoreEvent().listen([](GJUserScore* score) {
        // Do something
    }).leak();
}

// Node-based listener
class $modify(GJScoreCell) {
    void loadFromScore(GJUserScore* score) {
        GJScoreCell::loadFromScore(score);

        if (score->m_scoreType == 2) return;

        user_data::handleScoreCell(this, [this](GJUserScore* score) {
            // Do something
        });
    }
};

Level Leaderboard Events

#include 
#include 

// Global listener
$on_mod(Loaded) {
    user_data::LevelScoreEvent().listen([](GJUserScore* score) {
        // Do something
    }).leak();
}

// Node-based listener
class $modify(GJLevelScoreCell) {
    void loadFromScore(GJUserScore* score) {
        GJLevelScoreCell::loadFromScore(score);

        user_data::handleLevelScoreCell(this, [this](GJUserScore* score) {
            // Do something
        });
    }
};

User Search Events

#include 
#include 

// Global listener
$on_mod(Loaded) {
    user_data::SearchResultEvent().listen([](GJUserScore* score) {
        // Do something
    }).leak();
}

// Node-based listener
class $modify(GJScoreCell) {
    void loadFromScore(GJUserScore* score) {
        GJScoreCell::loadFromScore(score);

        if (score->m_scoreType != 2) return;

        user_data::handleScoreCell(this, [this](GJUserScore* score) {
            // Do something
        });
    }
};

Credits

License

This mod is licensed under the MIT License.

User Data API Changelog

v2.0.0 (2026-02-06)

  • Ported to Geometry Dash v2.208 / Geode SDK v5.0.0
  • Removed constant references from user_data::upload parameters

v1.2.4 (2025-10-25)

  • Reverted downloading logic changes from v1.2.0 due to bandwidth issues

v1.2.3 (2025-10-11)

  • Changed the server to a new one hosted by dankmeme01
  • Reduced the amount of data requested from the server when fetching account comments

v1.2.2 (2025-09-13)

  • Fixed a bug where the user_data::handle... functions would copy the lambda instead of moving it, causing issues with captures

v1.2.1 (2025-09-07)

  • Fixed hook priority not being set correctly (I blame GitHub Copilot for this one)

v1.2.0 (2025-09-07)

  • Changed downloading logic to download concurrently with vanilla requests
  • Added user_data::handle... helper functions to simplify event handling in table cells and profile pages
  • Added user_data::ProfileCommentEvent and user_data::ProfileCommentFilter for profile comments

v1.1.0 (2025-08-28)

  • Added user_data::downloading method to check if a node is currently downloading user data
  • Added user_data::ID constant for the mod ID
  • Added null checks for node pointers in API methods

v1.0.0 (2025-08-23)

  • Initial release

Original Site made by HJfod. Geode 2 parody-ish by MeFinity.

Geode-SDK is the property of the Geode Team.


This website (Geode 2, Codename Malachite) is not affiliated with the Geode Team in any way shape or form.