Custom leaderboards
General
Players pick a leaderboard provider in their settings. With "Custom", they paste the URL of any provider.
Everything a player sees then comes from their provider: map leaderboards, the global leaderboard, profiles, and the stats of every player in-game.
A provider is a JSON-over-HTTPS server. The neomod server calls it on the player's behalf, appending the paths below to the URL the player entered.
The URL must be
https:// and resolve to a public address. Redirects are not followed, and responses over 2 MB are dropped.
Score Feed
Pull every neomod score from the public feed, to rank them however you like:
GEThttps://neomod.net/api/v1/scores?after={score_id}&limit={limit}
URL Parameters
- after: int, id of the last score you got.
0starts from the first score - limit: int,
1to500, default100
Returns scores oldest first. Poll with the last id you got until the list comes back empty.
{"scores": [score, ...]}
Score ids count down from -1: newer scores have lower ids.
Players who hide their scores in their privacy settings are left out.
Score object
{
"id": -39,
"user_id": 11485313,
"username": "example",
"beatmap_md5": "050cf495f923947b859368de1ac33c36",
"country": 239,
"team": null,
"pp": 201.6,
"pp_version": 20251008,
"score": 2624294,
"max_combo": 293,
"n300": 531,
"n100": 70,
"n50": 2,
"ngeki": 77,
"nkatu": 28,
"nmiss": 7,
"passed": true,
"perfect": false,
"has_replay": true,
"speed": 1.2,
"flags": "1073741824",
"mods_extra": {"ar_override": 9.4},
"client": "neomod-release-43.07",
"created_at": "2025-09-17T22:15:12.439Z"
}
- id: int, negative for neomod scores
- country: int, osu! country id
- team: int | null, osu! team id
- pp: float, computed by neomod
- speed: float,
1without speed mods - flags: string, 64-bit mod flags in decimal
- mods_extra: object, other mod settings. Empty when unused
- created_at: string, ISO 8601
Other fields are as in osu!.
Stats
Stats are shown in-game, next to each player:
{
"pp": 4029,
"rank": 1,
"accuracy": 0.9871,
"play_count": 100,
"ranked_score": 0,
"total_score": 0
}
- pp: int,
0to65535 - rank: int, global rank.
0when unranked - accuracy: float,
0to1 - play_count, ranked_score, total_score: int
- seconds_played: int, optional. Time played shown on profiles, neomod's own count when left out
Values out of range are clamped. neomod caches stats for 5 minutes.
Provider Endpoints
Respond with JSON and a 2xx status. Any other status counts as a failure.
Map leaderboard
POST{url}/v1/beatmap/{md5}/scores
Body
{
"type": "country",
"viewer_id": 11485313,
"limit": 50,
"country": 239
}
- type: string,
global,country,friendorteam - viewer_id: int, player looking at the leaderboard
- limit: int, up to
50 - country: int, osu! country id. Only for
country - team: int, osu! team id. Only for
team - user_ids: [int], sorted ids of the viewer and their friends. Only for
friend - mods: object, only for modded leaderboards.
speedandflagsas in scores, plus themods_extrafields
A modded leaderboard request:
{
"type": "global",
"viewer_id": 11485313,
"limit": 50,
"mods": {"speed": 1.5, "flags": "16"}
}
Response
Best first, one score per player. With mods, only scores set with the same mods.
{"scores": [score, ...]}
Profile
GET{url}/v1/users/{id}/profile
Response
{
"stats": stats,
"top_scores": [score, ...],
"recent_scores": [score, ...],
"rank_history": [{"date": "2025-10-02", "rank": 1234}, ...]
}
Up to 20 scores each. stats is null for unknown players.
rank_history is optional: the player's global rank at the end of each of the last 90 days, oldest first. It draws the rank graph on their profile.
Profile scores also carry the map they were set on:
- beatmapset_id: int
- osu_json: object, the beatmap as returned by the osu! API, with
beatmapset
Player stats
POST{url}/v1/users/stats
Body
{"user_ids": [11485313, 2]}
Up to 256 ids.
Response
{"stats": {"11485313": stats}}
Leave out players you don't know.
Global leaderboard
GET{url}/v1/leaderboard?limit={limit}&offset={offset}
Response
{
"rows": [
{
"id": 11485313,
"username": "example",
"total_pp": 4029.5
},
...
]
}
Best first.
Score notifications
POST{url}/v1/scores/notify
Sent when a player using your provider submits a score, so their leaderboards update right away. Scores from other players only come from the feed.
Body
{
"score": score,
"beatmap": {
"beatmap_md5": "050cf495f923947b859368de1ac33c36",
"beatmap_id": 1179925,
"beatmapset_id": 556834
}
}
score has no username. Reply with any JSON, e.g. {"ok": true}.
